#if (FEATURE_MODE == 0)
#include "ctc_core_app.h"
#include "ctc_app_index.h"
#include "ctc_api.h"
#include "ctcs_api.h"
#include "ctc_hash.h"
#include "ctc_vector.h"
#include "ctc_opf.h"
#include "ctc_spool.h"
#include "ctc_warmboot.h"
#include "ctc_app_pon.h"

#if defined(TSINGMA)
#define APP_IS_TM       1
#define APP_IS_TMM      0
#define APP_FROM_TMM    0
#elif defined(TSINGMA_MX) || defined(TSINGMA_GX)
#define APP_IS_TM       0
#define APP_IS_TMM      1
#define APP_FROM_TMM    1
#endif

#if defined(TSINGMA) || defined(TSINGMA_MX) || defined(TSINGMA_GX)
#define CTC_APP_PON_CREAT_LOCK(lchip)                 \
    do                                                      \
    {                                                       \
        sal_mutex_create(&p_app_pon_master->mutex); \
        if (NULL == p_app_pon_master->mutex)        \
        {                                                   \
            CTC_ERROR_RETURN(CTC_E_NO_MEMORY);              \
        }                                                   \
    } while (0)

#define CTC_APP_PON_LOCK(lchip) \
    if(p_app_pon_master->mutex) sal_mutex_lock(p_app_pon_master->mutex)

#define CTC_APP_PON_UNLOCK(lchip) \
    if(p_app_pon_master->mutex) sal_mutex_unlock(p_app_pon_master->mutex)

#define CTC_ERROR_RETURN_APP_PON_UNLOCK(op)               \
    do                                                          \
    {                                                           \
        int32 rv = (op);                                        \
        if (rv < 0)                                             \
        {                                                       \
            sal_mutex_unlock(p_app_pon_master->mutex);  \
            return rv;                                          \
        }                                                       \
    } while (0)

#define CTC_APP_PON_VLAN_BITMAP    (CTC_MAX_VLAN_ID+1)/32
#define CTC_APP_PON_LIMIT_NUM_DISABLE 0xFFFFFFFF

#define CTC_APP_PON_DEFULAT_FID 1
#define CTC_APP_PON_SERVICE_HASH_SIZE  (16384)  /*65536/4*/

#define CTC_APP_PON_VLAN_ID_CHECK(val) \
do { \
    if ((val) > CTC_MAX_VLAN_ID)\
    {\
        return CTC_E_BADID;\
    }\
}while(0)

#define CTC_APP_PON_TUNNEL_VLAN_ID_CHECK(val) \
do { \
    if ((val) > 0xFFFF)\
    {\
        return CTC_E_BADID;\
    }\
}while(0)

#define CTC_APP_PON_VDEV_ID_CHECK(ID) \
do {\
    if ((ID) >= p_app_pon_master->vdev_num)\
        return CTC_E_INVALID_PARAM; \
}while(0)

#define CTC_APP_PON_INIT_CHECK() \
do {\
    if(NULL == p_app_pon_master) return CTC_E_NOT_INIT;\
}while(0);


#define CTC_APP_PON_API_CALL(api, lchip, ...) \
    api? api(lchip, ##__VA_ARGS__) : CTC_E_NONE

#define CTC_APP_PON_API_ERROR_RETURN(api, lchip, ...) \
{ \
    int32 ret = CTC_E_NOT_SUPPORT; \
    ret = api? api(lchip, ##__VA_ARGS__) : CTC_E_NONE; \
    ret = ( ret < 0 )? ctc_error_code_mapping(ret) : ret; \
    return ret;\
}

#define ENCODE_APP_PON_ACL_ENTRY_ID(pkt_type, logic_port)  (((pkt_type) << 16) | (logic_port))
#define CTC_APP_PON_ACL_HASH_FIELD_SEL_ID   (15)
#define CTC_APP_PON_SCL_HASH_FIELD_SEL_ID   (3)
#define CTC_APP_PON_SCL_FLOW_ENTRY_ID       (0x10000000)
uint32 g_app_pon_mode = 1;

enum ctc_app_pon_type_e
{
    CTC_APP_PON_TYPE_NONE,
    CTC_APP_PON_TYPE_NNI_PORT,
    CTC_APP_PON_TYPE_UNI_PORT,
    CTC_APP_PON_TYPE_GEM_PORT,
    CTC_APP_PON_TYPE_VLAN_PORT,
    CTC_APP_PON_TYPE_MAX
};
typedef enum ctc_app_pon_type_e ctc_app_pon_type_t;

#define CTC_APP_DBG_FUNC()          CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__)
#define CTC_APP_DBG_INFO(FMT, ...)  CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_INFO, FMT, ##__VA_ARGS__)
#define CTC_APP_DBG_ERROR(FMT, ...) CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, FMT, ##__VA_ARGS__)
#define CTC_APP_DBG_PARAM(FMT, ...) CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, FMT, ##__VA_ARGS__)
#define CTC_APP_DBG_DUMP(FMT, ...)  CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, FMT, ##__VA_ARGS__)

#define CTC_APP_DBG_PARAM_ST(param) CTC_APP_DBG_PARAM("%-40s :%10u\n", #param, p_vlan_port->param)

#define CTC_APP_PON_RSV_MCAST_GROUP_ID(id) (id+1)
#define ENCODE_MCAST_GROUP_ID(BASE, OFFSET) (BASE + OFFSET)
#define CTC_APP_PON_MAX_RSV_MC_GROUP_ID      5*1024
#define CTC_APP_PON_SCL_GROUP_ID 1

enum ctc_app_pon_opf_e
{
    CTC_APP_PON_OPF_LOGIC_PORT,  /*logic port*/
    CTC_APP_PON_OPF_LOGIC_PORT_ID,
    CTC_APP_PON_OPF_FID,
    CTC_APP_PON_OPF_MAX
};
typedef enum ctc_app_pon_opf_e ctc_app_pon_opf_t;

struct ctc_app_pon_bpe_gem_port_s
{
    uint16 lport;                      /**< [TM] local port */
    uint16 gem_vlan;                   /**< [TM] gem port vlaue */
    uint16 logic_port;                 /**< [TM] Logic port */
    uint8  pass_through_en;            /**< [TM] pass through enable/disable */
    uint8  mac_security;            /**< [TM] mac security : refer to ctc_maclimit_action_t */
};
typedef struct ctc_app_pon_bpe_gem_port_s ctc_app_pon_bpe_gem_port_t;

struct ctc_app_pon_fid_db_s
{
  uint16 vdev_id;              /**< [GB.D2] [in] virtual device Identification */
  uint16 pkt_svlan;            /**< [GB.D2] [in] svlan id in packet */
  uint16 pkt_cvlan;            /**< [GB.D2] [in] cvlan id in packet */
  uint16 mcast_id;             /**< [GB.D2] [in] mcast group base id */
  uint16 fid;                  /**< [GB.D2] [out] forwarding id */
  uint32 limit_count;
  uint32 limit_num;
  uint32 vlan_port_id;
  uint16 limit_action;
  uint16 is_pass_through;
};
typedef struct ctc_app_pon_fid_db_s ctc_app_pon_fid_db_t;

struct ctc_app_pon_uni_db_s
{
    uint8 flex_pon_cnt;
    uint8 flex_onu_cnt;
    uint8 vdev_id;
    uint8 isolated_id;
    uint8 vlan_range_grp;
    uint16 ref_cnt;
    uint32 mc_xlate_nhid;
    uint32 backup_port;
    uint8 backup_port_valid;
    uint8 swap_port_en;
    uint16 vn_tag;
    uint32 nh_iloop;
};
typedef struct ctc_app_pon_uni_db_s ctc_app_pon_uni_db_t;

struct ctc_app_pon_nni_port_db_s
{
    uint16 vdev_id;
    uint8 rx_en;
    uint8 rsv;
    uint32 port;
    uint32 nni_ad_index;
    uint32 nni_nh_id;
    uint32 nni_logic_port;
    uint32 mc_xlate_nhid;
};
typedef struct ctc_app_pon_nni_port_db_s ctc_app_pon_nni_port_db_t;

struct ctc_app_pon_s
{
    ctc_hash_t* nni_port_hash;
    ctc_hash_t* gem_port_hash;
    ctc_hash_t* vlan_port_hash;
    ctc_hash_t* vlan_port_key_hash;
    ctc_spool_t* fid_spool;

    uint16 gem_port_cnt[CTC_APP_PON_MAX_VDEV_NUM];
    uint16 vlan_port_cnt[CTC_APP_PON_MAX_VDEV_NUM];
    uint16 nni_port_cnt[CTC_APP_PON_MAX_VDEV_NUM];
    uint32 nni_port[CTC_APP_PON_MAX_VDEV_NUM];

    uint16 nni_logic_port[CTC_APP_PON_MAX_VDEV_NUM];
    uint32 nni_mcast_nhid[CTC_APP_PON_MAX_VDEV_NUM];
    uint8 uni_outer_isolate_en[CTC_APP_PON_MAX_VDEV_NUM];
    uint8 uni_inner_isolate_en[CTC_APP_PON_MAX_VDEV_NUM];
    uint8 unknown_mcast_drop_en[CTC_APP_PON_MAX_VDEV_NUM];
    uint16 default_mcast_group_id[CTC_APP_PON_MAX_VDEV_NUM];
    uint16 default_bcast_fid[CTC_APP_PON_MAX_VDEV_NUM];
    uint32 default_unknown_mcast_nhid[CTC_APP_PON_MAX_VDEV_NUM];
    uint32 default_unknown_bcast_nhid[CTC_APP_PON_MAX_VDEV_NUM];
    uint16 limit_count[CTC_APP_PON_MAX_VDEV_NUM];
    uint32 limit_num[CTC_APP_PON_MAX_VDEV_NUM];
    uint32 limit_action[CTC_APP_PON_MAX_VDEV_NUM];

    uint32 vlan_glb_vdev[CTC_APP_PON_VLAN_BITMAP];  /**<[TM] when bit set, the vlan will use global vdev vlan to add packet header*/
    uint8 fid_mode;
    uint8 vdev_mode;
    uint16 vdev_num;
    uint16 vdev_base_vlan;
    uint16 mcast_tunnel_vlan;
    uint16 bcast_tunnel_vlan;
    uint16 mcast_max_group_num;
    uint16 glb_default_bcast_fid;
    uint32 glb_unknown_mcast_nhid;
    uint32 glb_unknown_bcast_nhid;
    uint32 bcast_value_logic_port;
    ctc_app_pon_uni_db_t* p_port_pon;
    sal_mutex_t* mutex;
};
typedef struct ctc_app_pon_s ctc_app_pon_t;

struct ctc_app_pon_gem_port_db_s
{
    uint32 port;
    uint32 tunnel_value;

    uint32 logic_port;
    uint32 logic_port_ext[3];  /*logic_port for ipv6/pppoe*/
    uint32 ref_cnt;

    uint8  flag;
    uint8  igs_vlan_maping_use_flex;

    uint32 pon_downlink_nhid;      /*PON servie nexthop*/

    uint16 ingress_policer_id;
    uint16 egress_policer_id;
    uint16 vdev_id;
    uint16 vn_tag;

    uint8 pass_trough_en;
    uint8 mac_security;
    uint32 limit_num;
    uint32 limit_count;
    uint16 limit_action;
    uint16 egs_service_id;
};
typedef struct ctc_app_pon_gem_port_db_s ctc_app_pon_gem_port_db_t;

struct ctc_app_pon_db_s
{
    uint32 criteria;
    uint32 port;
    uint32 tunnel_value;
    uint16 match_svlan;
    uint16 match_cvlan;
    uint16 match_svlan_end;
    uint16 match_cvlan_end;
    uint8  match_pkt_type;
    ctc_acl_key_t flex_key;
    uint32 calc_key_len[0];
    uint32 logic_port;
    uint32 vlan_port_id;
    uint16 pkt_svlan;
    uint16 pkt_cvlan;
    uint8 logic_port_b_en;
    uint16 fid;
    uint32 xlate_nhid;

    ctc_app_pon_gem_port_db_t* p_gem_port_db;

    uint16 egress_policer_id;
    uint16 ingress_policer_id;
    uint16 vdev_id;
};
typedef struct ctc_app_pon_db_s ctc_app_pon_db_t;

struct ctc_app_pon_find_s
{
    uint32 logic_port;
    uint16 match_svlan;
    uint16 match_cvlan;

    ctc_app_pon_db_t* p_vlan_port_db;
    ctc_app_pon_gem_port_db_t* p_gem_port_db;
    ctc_app_pon_nni_port_db_t* p_nni_port_db;
};
typedef struct ctc_app_pon_find_s ctc_app_pon_find_t;

ctc_app_pon_t* p_app_pon_master = NULL;


extern int32 _ctc_app_pon_traverse_fid(uint8 limit_action, uint8 vdev_id);


STATIC int32
_ctc_app_pon_check(uint8 lchip, ctc_app_pon_type_t vlan_port_type, uint32 gport, uint32 vlan_port_id)
{
    uint8 gchip_id = 0;
    uint8 gchip_id_invalid = 0;
    uint8 is_linkagg_port = CTC_IS_LINKAGG_PORT(gport);
    uint32 value = 0;
    switch(vlan_port_type)
    {
        case CTC_APP_PON_TYPE_NNI_PORT:
            CTC_GLOBAL_PORT_CHECK(gport);
            CTC_ERROR_RETURN(ctc_get_gchip_id(lchip, &gchip_id));
            gchip_id_invalid = (gchip_id != CTC_MAP_GPORT_TO_GCHIP(gport)) && !is_linkagg_port;
            if (gchip_id_invalid)
            {
                CTC_APP_DBG_ERROR("Invalid gchip id!n");
                return CTC_E_INVALID_GLOBAL_PORT;
            }
            break;
        case CTC_APP_PON_TYPE_VLAN_PORT:
            if (vlan_port_id)
            {
                break;
            }
        case CTC_APP_PON_TYPE_GEM_PORT:
            CTC_ERROR_RETURN(ctc_port_get_capability(gport, CTC_PORT_CAP_TYPE_MAC_ID, &value));
        case CTC_APP_PON_TYPE_UNI_PORT:
            CTC_GLOBAL_PORT_CHECK(gport);
            CTC_ERROR_RETURN(ctc_get_gchip_id(lchip, &gchip_id));
            gchip_id_invalid = (gchip_id != CTC_MAP_GPORT_TO_GCHIP(gport)) && !is_linkagg_port;
            if (is_linkagg_port || gchip_id_invalid)
            {
                CTC_APP_DBG_ERROR("Linkagg port is not support or invalid gchip id!n");
                return CTC_E_INVALID_GLOBAL_PORT;
            }
            break;
        default :
            CTC_APP_DBG_DUMP("Error use app vlan port check function!\n");
            return CTC_E_NONE;
    }

    return CTC_E_NONE;
}

int32
_ctc_app_pon_alloc_nhid(uint8 lchip, uint32* p_nhid)
{
    ctc_app_index_t app_index;
    uint8 gchip_id = 0;

    ctc_get_gchip_id(lchip, &gchip_id);
    sal_memset(&app_index, 0, sizeof(app_index));
    app_index.gchip = gchip_id;
    app_index.index_type = CTC_APP_INDEX_TYPE_NHID;
    app_index.entry_num = 1;


    CTC_ERROR_RETURN(ctc_app_index_alloc(&app_index));

    *p_nhid = app_index.index;

    return 0;
}

int32
_ctc_app_pon_free_nhid(uint8 lchip, uint32 nhid)
{
    ctc_app_index_t app_index;
    uint8 gchip_id = 0;

    ctc_get_gchip_id(lchip, &gchip_id);
    sal_memset(&app_index, 0, sizeof(app_index));
    app_index.gchip = gchip_id;
    app_index.index_type = CTC_APP_INDEX_TYPE_NHID;
    app_index.entry_num = 1;
    app_index.index = nhid;

    ctc_app_index_free(&app_index);

    return 0;
}

int32
_ctc_app_pon_alloc_mcast_group_id(uint8 lchip, uint32  num, uint32* p_mcast_id)
{
    ctc_app_index_t app_index;
    uint8 gchip_id = 0;

    ctc_get_gchip_id(lchip, &gchip_id);
    sal_memset(&app_index, 0, sizeof(app_index));
    app_index.gchip = gchip_id;
    app_index.index_type = CTC_APP_INDEX_TYPE_MCAST_GROUP_ID;
    app_index.entry_num = num;


    CTC_ERROR_RETURN(ctc_app_index_alloc(&app_index));

    *p_mcast_id = app_index.index;

    return 0;
}

int32
_ctc_app_pon_free_mcast_group_id(uint8 lchip, uint32 num, uint32 mcast_id)
{
    ctc_app_index_t app_index;
    uint8 gchip_id = 0;

    ctc_get_gchip_id(lchip, &gchip_id);
    sal_memset(&app_index, 0, sizeof(app_index));
    app_index.gchip = gchip_id;
    app_index.index_type = CTC_APP_INDEX_TYPE_MCAST_GROUP_ID;
    app_index.entry_num = num;
    app_index.index = mcast_id;

    ctc_app_index_free(&app_index);

    return 0;
}

int32
_ctc_app_pon_match_gem_port(ctc_app_pon_gem_port_db_t* p_gem_port_db,
                                   ctc_app_pon_find_t* p_vlan_port_match)
{
    CTC_PTR_VALID_CHECK(p_vlan_port_match);
    CTC_PTR_VALID_CHECK(p_gem_port_db);

    if (p_gem_port_db->logic_port == p_vlan_port_match->logic_port)
    {
        p_vlan_port_match->p_gem_port_db = p_gem_port_db;
        return -1;
    }

    return 0;
}

ctc_app_pon_gem_port_db_t*
_ctc_app_pon_find_gem_port_db(uint8 lchip, uint32 logic_port)
{
    ctc_app_pon_find_t vlan_port_find;

    sal_memset(&vlan_port_find, 0, sizeof(vlan_port_find));

    vlan_port_find.logic_port = logic_port;
    ctc_hash_traverse(p_app_pon_master->gem_port_hash,
                      (hash_traversal_fn)_ctc_app_pon_match_gem_port, &vlan_port_find);

    return vlan_port_find.p_gem_port_db;
}

int32
_ctc_app_pon_match_nni_port(ctc_app_pon_nni_port_db_t* p_nni_port_db,
                                   ctc_app_pon_find_t* p_vlan_port_match)
{
    CTC_PTR_VALID_CHECK(p_vlan_port_match);
    CTC_PTR_VALID_CHECK(p_nni_port_db);

    if (p_nni_port_db->nni_logic_port == p_vlan_port_match->logic_port)
    {
        p_vlan_port_match->p_nni_port_db = p_nni_port_db;
        return -1;
    }

    return 0;
}

ctc_app_pon_nni_port_db_t*
_ctc_app_pon_find_nni_port(uint8 lchip, uint32 logic_port)
{
    ctc_app_pon_find_t vlan_port_find;

    sal_memset(&vlan_port_find, 0, sizeof(vlan_port_find));

    vlan_port_find.logic_port = logic_port;
    ctc_hash_traverse(p_app_pon_master->nni_port_hash,
                      (hash_traversal_fn)_ctc_app_pon_match_nni_port, &vlan_port_find);

    return vlan_port_find.p_nni_port_db;
}

int32
_ctc_app_pon_match_vlan_port(ctc_app_pon_db_t* p_vlan_port_db,
                                   ctc_app_pon_find_t* p_vlan_port_match)
{
    CTC_PTR_VALID_CHECK(p_vlan_port_match);
    CTC_PTR_VALID_CHECK(p_vlan_port_db);

    if (p_vlan_port_db->logic_port == p_vlan_port_match->logic_port)
    {
        p_vlan_port_match->p_vlan_port_db = p_vlan_port_db;
        return -1;
    }

    return 0;
}

ctc_app_pon_db_t*
_ctc_app_pon_find_vlan_port_db(uint8 lchip, uint32 logic_port)
{
    ctc_app_pon_find_t vlan_port_find;

    sal_memset(&vlan_port_find, 0, sizeof(vlan_port_find));

    vlan_port_find.logic_port = logic_port;
    ctc_hash_traverse(p_app_pon_master->vlan_port_hash,
                      (hash_traversal_fn)_ctc_app_pon_match_vlan_port, &vlan_port_find);

    return vlan_port_find.p_vlan_port_db;
}

STATIC uint32
_ctc_app_pon_hash_nni_port_make(ctc_app_pon_nni_port_db_t* p_nni_port_db)
{
    uint32 data;
    uint32 length = 0;

    data = p_nni_port_db->port;
    length = sizeof(uint32);

    return ctc_hash_caculate(length, (uint8*)&data);
}

STATIC bool
_ctc_app_pon_hash_nni_port_cmp(ctc_app_pon_nni_port_db_t* p_data0,
                                     ctc_app_pon_nni_port_db_t* p_data1)
{
    if (p_data0->port == p_data1->port)
    {
        return TRUE;
    }

    return FALSE;
}

STATIC uint32
_ctc_app_pon_hash_gem_port_make(ctc_app_pon_gem_port_db_t* p_gem_port_db)
{
    uint32 data[2] = {0};
    uint32 length = 0;

    data[0] = p_gem_port_db->port;
    data[1] = p_gem_port_db->tunnel_value;
    length = sizeof(uint32)*2;

    return ctc_hash_caculate(length, (uint8*)data);
}

STATIC bool
_ctc_app_pon_hash_gem_port_cmp(ctc_app_pon_gem_port_db_t* p_data0,
                                     ctc_app_pon_gem_port_db_t* p_data1)
{
    if (p_data0->port == p_data1->port &&
        p_data0->tunnel_value == p_data1->tunnel_value)
    {
        return TRUE;
    }

    return FALSE;
}

STATIC uint32
_ctc_app_pon_hash_make(ctc_app_pon_db_t* p_vlan_port_db)
{
    uint32 data;
    uint32 length = 0;

    data = p_vlan_port_db->vlan_port_id;

    length = sizeof(uint32);

    return ctc_hash_caculate(length, (uint8*)&data);
}

STATIC bool
_ctc_app_pon_hash_cmp(ctc_app_pon_db_t* p_data0,
                            ctc_app_pon_db_t* p_data1)
{
    if (p_data0->vlan_port_id == p_data1->vlan_port_id)
    {
        return TRUE;
    }

    return FALSE;
}

STATIC uint32
_ctc_app_pon_key_hash_make(ctc_app_pon_db_t* p_vlan_port_db)
{
    uint32 length = 0;

    length = CTC_OFFSET_OF(ctc_app_pon_db_t, calc_key_len);

    return ctc_hash_caculate(length, (uint8*)p_vlan_port_db);
}

STATIC bool
_ctc_app_pon_key_hash_cmp(ctc_app_pon_db_t *p_data0,
                            ctc_app_pon_db_t* p_data1)
{
    uint32 length = 0;

    length = CTC_OFFSET_OF(ctc_app_pon_db_t, calc_key_len);

    if (0 == sal_memcmp(p_data0, p_data1, length))
    {
        return TRUE;
    }

    return FALSE;
}

STATIC uint32
_ctc_app_pon_fid_hash_make(ctc_app_pon_fid_db_t* p_port_fid)
{
    uint32 length = 0;
    uint16 data[3] = {0};


    if (CTC_IS_BIT_SET(p_app_pon_master->vlan_glb_vdev[p_port_fid->pkt_svlan/32], p_port_fid->pkt_svlan%32))
    {
        data[0] = p_port_fid->pkt_svlan;
        data[1] = 0;
        data[2] = 0;
    }
    else if (p_app_pon_master->fid_mode)
    {
        data[0] = p_port_fid->pkt_svlan;
        data[1] = 0;
        data[2] = p_app_pon_master->fid_mode?p_port_fid->vdev_id:0;
    }
    else
    {
        data[0] = p_port_fid->pkt_svlan;
        data[1] = p_port_fid->pkt_cvlan;
        data[2] = p_port_fid->vdev_id;
    }

    length = sizeof(data);

    return ctc_hash_caculate(length, (uint8*)data);
}

STATIC bool
_ctc_app_pon_fid_hash_cmp(ctc_app_pon_fid_db_t* p_data0,
                                       ctc_app_pon_fid_db_t* p_data1)
{
    if (((p_data0->pkt_svlan == p_data1->pkt_svlan)
        && (p_data0->pkt_cvlan == p_data1->pkt_cvlan || p_app_pon_master->fid_mode)
        && (p_data0->vdev_id == p_data1->vdev_id))
        || (CTC_IS_BIT_SET(p_app_pon_master->vlan_glb_vdev[p_data0->pkt_svlan/32], p_data0->pkt_svlan%32)
        && (p_data0->pkt_svlan == p_data1->pkt_svlan)))
    {
        return TRUE;
    }

    return FALSE;
}

int32
_ctc_app_pon_remove_uplink_svlan_entry(uint8 lchip, uint32 logic_port, ctc_app_pon_fid_db_t* port_fid_db)
{
    ctc_app_pon_gem_port_db_t* p_gem_port_find = NULL;
    ctc_app_pon_db_t* p_vlan_port_db = NULL;
    ctc_pon_vlan_port_t vlan_port;
    ctc_app_pon_db_t p_vlan_port_temp;
    ctc_opf_t opf;

    sal_memset(&p_vlan_port_temp, 0, sizeof(p_vlan_port_temp));
    p_gem_port_find = _ctc_app_pon_find_gem_port_db(lchip, logic_port);
    if(NULL == p_gem_port_find)
    {
        return CTC_E_ENTRY_NOT_EXIST;
    }
    p_vlan_port_temp.port= p_gem_port_find->port;
    p_vlan_port_temp.tunnel_value = p_gem_port_find->tunnel_value;
    p_vlan_port_temp.match_svlan = port_fid_db->pkt_svlan;
    p_vlan_port_temp.match_cvlan = port_fid_db->pkt_cvlan;
    p_vlan_port_temp.logic_port = logic_port;

    p_vlan_port_db = ctc_hash_lookup(p_app_pon_master->vlan_port_key_hash, &p_vlan_port_temp);

    if (NULL == p_vlan_port_db)
    {
        return CTC_E_ENTRY_NOT_EXIST;
    }

    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_PON_SERVICE);
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_UNI);
    vlan_port.gport = p_vlan_port_db->port;
    vlan_port.tunnel_value = p_vlan_port_db->tunnel_value;
    vlan_port.vlan_port_id = p_vlan_port_db->vlan_port_id;
    ctc_pon_destroy_vlan_port(&vlan_port);

    sal_memset(&opf, 0, sizeof(opf));
    opf.pool_type = CTC_OPF_VLAN_PORT;
    opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT_ID;
    ctc_opf_free_offset(&opf, 1, p_vlan_port_db->vlan_port_id);

    ctc_hash_remove(p_app_pon_master->vlan_port_key_hash, p_vlan_port_db);

    return CTC_E_NONE;
}

extern int32
_ctc_app_pon_destroy_downlink_service(uint8 lchip, uint32 vlan_port_id, uint8 vdev_id, uint16 pkt_svlan);

STATIC int32
_ctc_app_pon_remove_fdb_learn_with_def_fid(uint8 lchip, ctc_app_pon_fid_db_t* p_port_fid_db)
{
    ctc_app_pon_fid_db_t port_fid_db;
    ctc_app_pon_fid_db_t* port_fid_db_temp = NULL;

    sal_memset(&port_fid_db, 0, sizeof(ctc_app_pon_fid_db_t));
    port_fid_db.vdev_id = p_port_fid_db->vdev_id;
    port_fid_db.pkt_svlan = p_port_fid_db->pkt_svlan;
    port_fid_db.pkt_cvlan = p_app_pon_master->fid_mode?0:p_port_fid_db->pkt_cvlan;
    port_fid_db_temp = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
    if(NULL == port_fid_db_temp)
    {
        return CTC_E_ENTRY_NOT_EXIST;
    }
    ctc_spool_remove(p_app_pon_master->fid_spool, &port_fid_db, NULL);

    _ctc_app_pon_destroy_downlink_service(lchip, port_fid_db_temp->vlan_port_id, p_port_fid_db->vdev_id,  p_port_fid_db->pkt_svlan);

    return CTC_E_NONE;
}

STATIC bool
_ctc_app_pon_fid_build_index(ctc_app_pon_fid_db_t* p_port_fid_db, uint8* p_lchip)
{
    uint8 lchip = 0;
    uint16 vlan_glb_vdev_en = 1;
    uint32 fid = 0;
    uint32 mcast_id = 0;
    uint32 nh_profile_id = 0;
    uint32 nh_id = 0;
    uint32 nh_mcast_id = 0;
    uint32 vlan_port_id = 0;
    uint8 alloc_num = 1;
    ctc_opf_t opf;
    ctc_l2dflt_addr_t l2dflt;
    ctc_mcast_nh_param_group_t mcast_group;
    int32 ret = CTC_E_NONE;

    CTC_PTR_VALID_CHECK(p_port_fid_db);

    lchip = *p_lchip;
    sal_memset(&opf, 0, sizeof(opf));
    opf.pool_type = CTC_OPF_VLAN_PORT;
    opf.pool_index = CTC_APP_PON_OPF_FID;

    CTC_ERROR_RETURN(ctc_opf_alloc_offset(&opf, 1, &fid));
    p_port_fid_db->fid = fid;
    p_port_fid_db->limit_num = CTC_APP_PON_LIMIT_NUM_DISABLE;
    CTC_ERROR_GOTO(_ctc_app_pon_alloc_mcast_group_id(lchip, 2, &mcast_id), ret, roll_back_0);
    p_port_fid_db->mcast_id = mcast_id;
    sal_memset(&l2dflt, 0, sizeof(l2dflt));
    l2dflt.fid = fid;
    l2dflt.l2mc_grp_id = ENCODE_MCAST_GROUP_ID(mcast_id, 0);
    CTC_SET_FLAG(l2dflt.flag, CTC_L2_DFT_VLAN_FLAG_USE_LOGIC_PORT);
    CTC_ERROR_GOTO(ctc_l2_add_default_entry(&l2dflt), ret, roll_back_1);

    CTC_ERROR_GOTO(_ctc_app_pon_alloc_nhid(lchip, &nh_mcast_id), ret, roll_back_2);
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.mc_grp_id = ENCODE_MCAST_GROUP_ID(mcast_id, 1);
    CTC_ERROR_GOTO(ctc_nh_add_mcast(nh_mcast_id, &mcast_group), ret, roll_back_3);
    ctc_l2_set_fid_property(fid, CTC_L2_FID_PROP_BDING_MCAST_GROUP, ENCODE_MCAST_GROUP_ID(p_port_fid_db->mcast_id, 1));

    vlan_glb_vdev_en = CTC_IS_BIT_SET(p_app_pon_master->vlan_glb_vdev[p_port_fid_db->pkt_svlan/32], p_port_fid_db->pkt_svlan%32);
    if(vlan_glb_vdev_en)
    {
        alloc_num = p_app_pon_master->vdev_num;
    }
    sal_memset(&opf, 0, sizeof(opf));
    opf.pool_type = CTC_OPF_VLAN_PORT;
    opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT_ID;
    CTC_ERROR_GOTO(ctc_opf_alloc_offset(&opf, alloc_num, &vlan_port_id), ret, roll_back_0);
    p_port_fid_db->vlan_port_id = vlan_port_id;
        /*Add MC member*/
    nh_profile_id = vlan_glb_vdev_en? p_app_pon_master->glb_unknown_mcast_nhid:p_app_pon_master->default_unknown_mcast_nhid[p_port_fid_db->vdev_id];
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.mc_grp_id = ENCODE_MCAST_GROUP_ID(mcast_id, 1);
    mcast_group.opcode = CTC_NH_PARAM_MCAST_ADD_MEMBER;
    mcast_group.mem_info.ref_nhid = nh_profile_id;
    mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
    CTC_ERROR_GOTO(ctc_nh_update_mcast(nh_mcast_id, &mcast_group), ret, roll_back_4);

    /*Add BC member*/
    nh_profile_id = vlan_glb_vdev_en? p_app_pon_master->glb_unknown_bcast_nhid:p_app_pon_master->default_unknown_bcast_nhid[p_port_fid_db->vdev_id];
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.mc_grp_id = ENCODE_MCAST_GROUP_ID(mcast_id, 0);
    mcast_group.opcode = CTC_NH_PARAM_MCAST_ADD_MEMBER;
    mcast_group.mem_info.ref_nhid = nh_profile_id;
    mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
    ctc_nh_get_mcast_nh(ENCODE_MCAST_GROUP_ID(mcast_id, 0), &nh_id);
    CTC_ERROR_GOTO(ctc_nh_update_mcast(nh_id, &mcast_group), ret, roll_back_4);

    return CTC_E_NONE;
roll_back_4:
    ctc_l2_set_fid_property(fid, CTC_L2_FID_PROP_BDING_MCAST_GROUP, 0);
    CTC_APP_DBG_ERROR("mcast nexthop id error!!\n");
    ctc_nh_remove_mcast(nh_mcast_id);
roll_back_3:
    CTC_APP_DBG_ERROR("free nhid !!\n");
    _ctc_app_pon_free_nhid(lchip, nh_mcast_id);
roll_back_2:
    CTC_APP_DBG_ERROR("remove default entry !!\n");
    sal_memset(&l2dflt, 0, sizeof(l2dflt));
    l2dflt.fid = fid;
    l2dflt.l2mc_grp_id = ENCODE_MCAST_GROUP_ID(mcast_id, 0);
    CTC_SET_FLAG(l2dflt.flag, CTC_L2_DFT_VLAN_FLAG_USE_LOGIC_PORT);
    ctc_l2_remove_default_entry(&l2dflt);

roll_back_1:
    CTC_APP_DBG_ERROR("The mcast group error!\n");
    _ctc_app_pon_free_mcast_group_id(lchip, 2, mcast_id);

roll_back_0:
    sal_memset(&opf, 0, sizeof(opf));
    opf.pool_type = CTC_OPF_VLAN_PORT;
    opf.pool_index = CTC_APP_PON_OPF_FID;

    ctc_opf_free_offset(&opf, 1, fid);

    return ret;
}

/* free index of HASH ad */
STATIC bool
_ctc_app_pon_fid_free_index(ctc_app_pon_fid_db_t* p_port_fid_db, uint8* p_lchip)
{
    uint8 lchip = 0;
    uint8 alloc_num = 1;
    uint8 vlan_glb_vdev_en = 0;
    uint32 nh_id = 0;
    uint32 vlan_port_id = 0;
    ctc_opf_t opf;
    ctc_l2dflt_addr_t l2dflt;
    ctc_mcast_nh_param_group_t mcast_group;

    CTC_PTR_VALID_CHECK(p_port_fid_db);

    lchip = *p_lchip;
    ctc_l2_set_fid_property(p_port_fid_db->fid, CTC_L2_FID_PROP_BDING_MCAST_GROUP, ENCODE_MCAST_GROUP_ID(p_port_fid_db->mcast_id, 0));
    sal_memset(&l2dflt, 0, sizeof(l2dflt));
    l2dflt.fid = p_port_fid_db->fid;
    l2dflt.l2mc_grp_id = ENCODE_MCAST_GROUP_ID(p_port_fid_db->mcast_id, 0);
    CTC_SET_FLAG(l2dflt.flag, CTC_L2_DFT_VLAN_FLAG_USE_LOGIC_PORT);
    ctc_l2_remove_default_entry(&l2dflt);

    sal_memset(&opf, 0, sizeof(opf));
    opf.pool_type = CTC_OPF_VLAN_PORT;
    opf.pool_index = CTC_APP_PON_OPF_FID;
    ctc_opf_free_offset(&opf, 1, p_port_fid_db->fid);

    vlan_glb_vdev_en = CTC_IS_BIT_SET(p_app_pon_master->vlan_glb_vdev[p_port_fid_db->pkt_svlan/32], p_port_fid_db->pkt_svlan%32);
    if(vlan_glb_vdev_en)
    {
        alloc_num = p_app_pon_master->vdev_num;
    }
    vlan_port_id = p_port_fid_db->vlan_port_id;
    sal_memset(&opf, 0, sizeof(opf));
    opf.pool_type = CTC_OPF_VLAN_PORT;
    opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT_ID;
    ctc_opf_free_offset(&opf, alloc_num, vlan_port_id);

    ctc_nh_get_mcast_nh(ENCODE_MCAST_GROUP_ID(p_port_fid_db->mcast_id, 1), &nh_id);
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.mc_grp_id = ENCODE_MCAST_GROUP_ID(p_port_fid_db->mcast_id, 1);
    ctc_nh_remove_mcast(nh_id);
    _ctc_app_pon_free_nhid(lchip, nh_id);

    _ctc_app_pon_free_mcast_group_id(lchip, 2, p_port_fid_db->mcast_id);

    return CTC_E_NONE;
}

int32
ctc_app_pon_get_by_logic_port(uint8 lchip, uint32 logic_port, ctc_app_pon_service_t* p_vlan_port)
{
    ctc_app_pon_db_t* p_vlan_port_find = NULL;
    ctc_app_pon_gem_port_db_t* p_gem_port_find = NULL;
    ctc_app_pon_nni_port_db_t* p_nni_port_find = NULL;

    /* CHECK */
    CTC_PTR_VALID_CHECK(p_vlan_port);
    CTC_APP_PON_INIT_CHECK();

    p_vlan_port_find = _ctc_app_pon_find_vlan_port_db(lchip, logic_port);

    if (p_vlan_port_find)
    {
        p_vlan_port->vlan_port_id = p_vlan_port_find->vlan_port_id;
        p_vlan_port->criteria = p_vlan_port_find->criteria;
        p_vlan_port->port = p_vlan_port_find->port;
        p_vlan_port->match_tunnel_value = p_vlan_port_find->tunnel_value;
        p_vlan_port->match_svlan = p_vlan_port_find->match_svlan;
        p_vlan_port->match_cvlan = p_vlan_port_find->match_cvlan;
        p_vlan_port->match_svlan_end = p_vlan_port_find->match_svlan_end;
        p_vlan_port->match_cvlan_end = p_vlan_port_find->match_cvlan_end;
        sal_memcpy(&p_vlan_port->flex_key, &p_vlan_port_find->flex_key, sizeof(ctc_acl_key_t));
        p_vlan_port->logic_port = p_vlan_port_find->logic_port;

        return CTC_E_NONE;
    }

    p_gem_port_find = _ctc_app_pon_find_gem_port_db(lchip, logic_port);
    if (p_gem_port_find)
    {
        p_vlan_port->port = p_gem_port_find->port;
        p_vlan_port->match_tunnel_value = p_gem_port_find->tunnel_value;
        p_vlan_port->logic_port = p_gem_port_find->logic_port;
        return CTC_E_NONE;
    }

    p_nni_port_find = _ctc_app_pon_find_nni_port(lchip, logic_port);
    if (p_nni_port_find)
    {
        p_vlan_port->port = p_nni_port_find->port;
        return CTC_E_NONE;
    }

    return CTC_E_NOT_EXIST;
}

STATIC int32
_ctc_app_pon_compare_fid(void* node, void* user_data)
{
    ctc_app_pon_fid_db_t* p_port_fid_db = (ctc_app_pon_fid_db_t*)(((ctc_spool_node_t*)node)->data);
    ctc_app_pon_fid_db_t* p_port_fid_db_data = (ctc_app_pon_fid_db_t*)user_data;

    if (p_port_fid_db->fid == p_port_fid_db_data->fid)
    {
        p_port_fid_db_data->vdev_id = p_port_fid_db->vdev_id;
        p_port_fid_db_data->pkt_svlan = p_port_fid_db->pkt_svlan;
        p_port_fid_db_data->pkt_cvlan = p_port_fid_db->pkt_cvlan;
        p_port_fid_db_data->is_pass_through = p_port_fid_db->is_pass_through;
        p_port_fid_db_data->limit_num = p_port_fid_db->limit_num;
        p_port_fid_db_data->limit_count = p_port_fid_db->limit_count;
        p_port_fid_db_data->limit_action = p_port_fid_db->limit_action;
        p_port_fid_db_data->mcast_id = p_port_fid_db->mcast_id;
        return -1;
    }
    return CTC_E_NONE;
}

int32
_ctc_app_pon_get_fid_by_fid(ctc_app_pon_fid_db_t* p_port_fid_db)
{
    CTC_ERROR_RETURN(ctc_spool_traverse(p_app_pon_master->fid_spool,
                          (spool_traversal_fn)_ctc_app_pon_compare_fid, p_port_fid_db));

    return CTC_E_NONE;
}

int32
ctc_app_pon_get_fid_mapping_info(uint8 lchip, ctc_app_pon_fid_t* p_port_fid)
{
    int32 ret = CTC_E_NONE;
    ctc_app_pon_fid_db_t port_fid_db;
    ctc_app_pon_fid_db_t* p_port_fid_temp = NULL;

    /* CHECK */
    CTC_PTR_VALID_CHECK(p_port_fid);
    CTC_APP_PON_INIT_CHECK();
    CTC_APP_PON_VDEV_ID_CHECK(p_port_fid->vdev_id);

    /* Debug */
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "vDev id",      p_port_fid->vdev_id);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "packet svlan",         p_port_fid->pkt_svlan);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "packet cvlan",         p_port_fid->pkt_cvlan);

    sal_memset(&port_fid_db, 0, sizeof(ctc_app_pon_fid_db_t));
    CTC_APP_PON_LOCK(lchip);

    port_fid_db.fid = p_port_fid->fid;
    port_fid_db.pkt_svlan = p_port_fid->pkt_svlan;
    port_fid_db.pkt_cvlan = p_app_pon_master->fid_mode?0:p_port_fid->pkt_cvlan;
    port_fid_db.vdev_id = p_port_fid->vdev_id;
    if (port_fid_db.fid)
    {
        ret = _ctc_app_pon_get_fid_by_fid(&port_fid_db);
        if (!ret)
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NOT_EXIST;
        }
        p_port_fid->pkt_svlan = port_fid_db.pkt_svlan;
        p_port_fid->pkt_cvlan = port_fid_db.pkt_cvlan;
        p_port_fid->vdev_id = port_fid_db.vdev_id;
    }
    else
    {
        p_port_fid_temp = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);

        if (NULL == p_port_fid_temp)
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NOT_EXIST;
        }
        p_port_fid->fid = p_port_fid_temp->fid;
    }
    CTC_APP_PON_UNLOCK(lchip);

    CTC_APP_DBG_INFO("Fid: %u!\n", p_port_fid->fid);

    return CTC_E_NONE;
}

extern int32
_ctc_app_pon_create_downlink_service(uint8 lchip, ctc_app_pon_service_t* p_vlan_port, ctc_app_pon_fid_db_t* p_port_fid_db);

int32
ctc_app_pon_alloc_fid(uint8 lchip, ctc_app_pon_fid_t* p_port_fid)
{
    int32 ret = CTC_E_NONE;
    ctc_app_pon_fid_db_t port_fid_db;
    ctc_app_pon_fid_db_t* p_port_fid_temp = NULL;

    /* CHECK */
    CTC_PTR_VALID_CHECK(p_port_fid);
    CTC_APP_PON_INIT_CHECK();
    CTC_APP_PON_VLAN_ID_CHECK(p_port_fid->pkt_svlan);
    CTC_APP_PON_VLAN_ID_CHECK(p_port_fid->pkt_cvlan);
    CTC_APP_PON_VDEV_ID_CHECK(p_port_fid->vdev_id);
    if (0 == p_app_pon_master->nni_port_cnt[p_port_fid->vdev_id])
    {
        return CTC_E_NOT_EXIST;
    }

    /* Debug */
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "vDev id",              p_port_fid->vdev_id);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "packet svlan",         p_port_fid->pkt_svlan);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "packet cvlan",         p_port_fid->pkt_cvlan);

    sal_memset(&port_fid_db, 0, sizeof(ctc_app_pon_fid_db_t));
    CTC_APP_PON_LOCK(lchip);

    port_fid_db.pkt_svlan = p_port_fid->pkt_svlan;
    port_fid_db.pkt_cvlan = p_app_pon_master->fid_mode?0:p_port_fid->pkt_cvlan;
    port_fid_db.vdev_id = p_port_fid->vdev_id;

    p_port_fid_temp = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
    if (p_port_fid_temp)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_EXIST;
    }

    ret = ctc_spool_add(p_app_pon_master->fid_spool, &port_fid_db, NULL, &p_port_fid_temp);
    if (ret)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return ret;
    }
    ret = _ctc_app_pon_create_downlink_service(lchip, NULL, p_port_fid_temp);
    if(ret)
    {
        ctc_spool_remove(p_app_pon_master->fid_spool, &port_fid_db, NULL);
        CTC_APP_PON_UNLOCK(lchip);
        return ret;
    }
    p_port_fid->fid = p_port_fid_temp->fid;
    CTC_APP_PON_UNLOCK(lchip);

    CTC_APP_DBG_INFO("Fid: %u!\n", p_port_fid_temp->fid);

    return CTC_E_NONE;
}

int32
ctc_app_pon_free_fid(uint8 lchip, ctc_app_pon_fid_t* p_port_fid)
{
    int32 ret = CTC_E_NONE;
    ctc_app_pon_fid_db_t port_fid_db;
    ctc_app_pon_fid_db_t* p_port_fid_temp = NULL;
    uint32 nni_vlan_port_id;

    /* CHECK */
    CTC_PTR_VALID_CHECK(p_port_fid);
    CTC_APP_PON_INIT_CHECK();
    CTC_APP_PON_VLAN_ID_CHECK(p_port_fid->pkt_svlan);
    CTC_APP_PON_VLAN_ID_CHECK(p_port_fid->pkt_cvlan);
    CTC_APP_PON_VDEV_ID_CHECK(p_port_fid->vdev_id);

    /* Debug */
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "vDev id",      p_port_fid->vdev_id);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "packet svlan",         p_port_fid->pkt_svlan);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "packet cvlan",         p_port_fid->pkt_cvlan);

    CTC_APP_PON_LOCK(lchip);

    sal_memset(&port_fid_db, 0, sizeof(ctc_app_pon_fid_db_t));

    port_fid_db.fid = p_port_fid->fid;
    port_fid_db.pkt_svlan = p_port_fid->pkt_svlan;
    port_fid_db.pkt_cvlan = p_app_pon_master->fid_mode?0:p_port_fid->pkt_cvlan;
    port_fid_db.vdev_id = p_port_fid->vdev_id;

    p_port_fid_temp = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
    if (NULL == p_port_fid_temp)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }
    nni_vlan_port_id = p_port_fid_temp->vlan_port_id;
    ret = ctc_spool_remove(p_app_pon_master->fid_spool, &port_fid_db, NULL);
    if (ret)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return ret;
    }
    p_port_fid_temp = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
    if(NULL == p_port_fid_temp)
    {
        _ctc_app_pon_destroy_downlink_service(lchip, nni_vlan_port_id, p_port_fid->vdev_id, p_port_fid->pkt_svlan);
    }
    CTC_APP_PON_UNLOCK(lchip);

    CTC_APP_DBG_INFO("Fid: %u!\n", p_port_fid->fid);

    return CTC_E_NONE;
}

int32
_ctc_app_pon_get_uni_port(uint8 lchip, uint32 port, ctc_app_pon_uni_db_t** pp_uni_port)
{
    uint16 lport = 0;

    lport = CTC_MAP_GPORT_TO_LPORT(port);
    *pp_uni_port = &p_app_pon_master->p_port_pon[lport];

    return CTC_E_NONE;
}

#define _______DUMP________

STATIC int32
_ctc_app_pon_show_gem_port_all(ctc_app_pon_gem_port_db_t* p_gem_port_db,
                                 uint32* i)
{
    CTC_PTR_VALID_CHECK(i);
    CTC_PTR_VALID_CHECK(p_gem_port_db);

    CTC_APP_DBG_DUMP("%-5u %5u %15u %15u %15u\n",
               *i,
               p_gem_port_db->port,
               p_gem_port_db->tunnel_value,
               p_gem_port_db->logic_port,
               p_gem_port_db->ref_cnt);
    (*i)++;

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_show_vlan_port_all(ctc_app_pon_db_t* p_vlan_port_db,
                                  uint32* i)
{
   CTC_PTR_VALID_CHECK(i);
   CTC_PTR_VALID_CHECK(p_vlan_port_db);


   CTC_APP_DBG_DUMP("%-5u %5u %5u %15u %10u %10u %10u %15u\n",
              *i,
              p_vlan_port_db->vlan_port_id,
              p_vlan_port_db->port,
              p_vlan_port_db->tunnel_value,
              p_vlan_port_db->match_svlan,
              p_vlan_port_db->match_cvlan,
              p_vlan_port_db->match_svlan_end,
              p_vlan_port_db->logic_port);
    (*i)++;

    return CTC_E_NONE;
}

int32
_ctc_app_pon_show_uni_port(uint8 lchip, uint8 detail, uint32 port)
{
    uint16 lport = 0;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;

    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_UNI_PORT, port, 0));
    lport = CTC_MAP_GPORT_TO_LPORT(port);

    p_uni_port = &p_app_pon_master->p_port_pon[lport];
    if (0 == p_uni_port->isolated_id)
    {
        return CTC_E_NOT_EXIST;
    }

    CTC_APP_DBG_DUMP("port: 0x%x detail:\n", port);
    CTC_APP_DBG_DUMP("---------------------------------------------------------------------------------------------\n");
    CTC_APP_DBG_DUMP("%-40s : %10u\n" , "uni index"        , p_uni_port->isolated_id);
    CTC_APP_DBG_DUMP("%-40s : %10u\n" , "ref_cnt"          , p_uni_port->ref_cnt);
    CTC_APP_DBG_DUMP("%-40s : %10u\n" , "mc_xlate_nhid"    , p_uni_port->mc_xlate_nhid);

    CTC_APP_DBG_DUMP("%-40s : %10u\n" , "vlan_range_grp"   , p_uni_port->vlan_range_grp);
    CTC_APP_DBG_DUMP("%-40s : %10u\n" , "backup_port_valid"   , p_uni_port->backup_port_valid);
    CTC_APP_DBG_DUMP("%-40s : %10u\n" , "backup_port"   , p_uni_port->backup_port);
    CTC_APP_DBG_DUMP("%-40s : %10u\n" , "swap_port_en"   , p_uni_port->swap_port_en);

    return CTC_E_NONE;
}

int32
_ctc_app_pon_show_nni_port(uint8 lchip, uint32 port)
{
    ctc_app_pon_nni_port_db_t nni_port_db;
    ctc_app_pon_nni_port_db_t* p_nni_port_db = NULL;

    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_NNI_PORT, port, 0));

    /* DB */
    sal_memset(&nni_port_db, 0, sizeof(nni_port_db));
    nni_port_db.port = port;
    p_nni_port_db = ctc_hash_lookup(p_app_pon_master->nni_port_hash, &nni_port_db);
    if (NULL == p_nni_port_db)
    {
        return CTC_E_NOT_EXIST;
    }

    CTC_APP_DBG_DUMP("port: 0x%x detail:\n", port);
    CTC_APP_DBG_DUMP("---------------------------------------------------------------------------------------------\n");
    CTC_APP_DBG_DUMP("%-40s : %10u\n" , "vDev ID"      , p_nni_port_db->vdev_id);
    CTC_APP_DBG_DUMP("%-40s : %10u\n" , "Logic Port"   , p_nni_port_db->nni_logic_port);
    CTC_APP_DBG_DUMP("%-40s : %10s\n" , "Rx Enable"       , p_nni_port_db->rx_en?"Enable":"Disable");

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_show_gem_port(uint8 lchip, uint8 detail, uint32 port, uint32 tunnel_value)
{

    if (0 == detail)
    {
        uint32 i = 1;
        CTC_APP_DBG_DUMP("%-5s %5s %15s %15s %15s\n", "No.", "port", "tunnel-value", "logic port", "ref cnt");
        CTC_APP_DBG_DUMP("-----------------------------------------------------------------\n");

        ctc_hash_traverse(p_app_pon_master->gem_port_hash,
                          (hash_traversal_fn)_ctc_app_pon_show_gem_port_all, &i);
    }
    else
    {
        ctc_app_pon_gem_port_db_t gem_port_db;
        ctc_app_pon_gem_port_db_t* p_gem_port_db = NULL;

        /* DB */
        sal_memset(&gem_port_db, 0, sizeof(gem_port_db));
        gem_port_db.port = port;
        gem_port_db.tunnel_value = tunnel_value;
        p_gem_port_db = ctc_hash_lookup(p_app_pon_master->gem_port_hash, &gem_port_db);
        if (NULL == p_gem_port_db)
        {
            return CTC_E_NOT_EXIST;
        }

        CTC_APP_DBG_DUMP("port: 0x%x  tunnel-value:%u detail:\n", port, tunnel_value);
        CTC_APP_DBG_DUMP("---------------------------------------------------------------------------------------------\n");
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "ref_cnt"      , p_gem_port_db->ref_cnt);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "flag"         , p_gem_port_db->flag);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "logic_port"   , p_gem_port_db->logic_port);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "pon downlink nhid"  , p_gem_port_db->pon_downlink_nhid);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "ingress_policer_id" , p_gem_port_db->ingress_policer_id);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "egress_policer_id"  , p_gem_port_db->egress_policer_id);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "pass through"       , p_gem_port_db->pass_trough_en);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "mac security"       , p_gem_port_db->mac_security);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "vdev_id"       , p_gem_port_db->vdev_id);
    }

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_show_vlan_port(uint8 lchip, uint8 detail, uint32 vlan_port_id)
{

    if (0 == detail)
    {
        uint32 i = 1;
        CTC_APP_DBG_DUMP("%-5s %5s %5s %15s %10s %10s %10s %15s\n", "No.", "id", "port", "tunnel-value", "svid", "cvid", "svid-end", "logic port");
        CTC_APP_DBG_DUMP("----------------------------------------------------------------------------------------------------------------------\n");

        ctc_hash_traverse(p_app_pon_master->vlan_port_hash,
                          (hash_traversal_fn)_ctc_app_pon_show_vlan_port_all, &i);
    }
    else
    {
        ctc_app_pon_db_t vlan_port_db;
        ctc_app_pon_db_t* p_vlan_port_db = NULL;
        sal_memset(&vlan_port_db, 0, sizeof(vlan_port_db));
        vlan_port_db.vlan_port_id = vlan_port_id;

        p_vlan_port_db = ctc_hash_lookup(p_app_pon_master->vlan_port_hash, &vlan_port_db);

        if (NULL == p_vlan_port_db)
        {
            return CTC_E_NOT_EXIST;
        }

        CTC_APP_DBG_DUMP("vlan-port-id: %u detail:\n", vlan_port_id);
        CTC_APP_DBG_DUMP("---------------------------------------------------------------------------------------------\n");
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "criteria"            , p_vlan_port_db->criteria);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "port"                , p_vlan_port_db->port);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "tunnel_value"        , p_vlan_port_db->tunnel_value);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "match_svlan"         , p_vlan_port_db->match_svlan);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "match_cvlan"         , p_vlan_port_db->match_cvlan);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "match_svlan_end"     , p_vlan_port_db->match_svlan_end);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "match_cvlan_end"     , p_vlan_port_db->match_cvlan_end);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "logic_port"          , p_vlan_port_db->logic_port);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "pkt-svlan"           , p_vlan_port_db->pkt_svlan);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "pkt-cvlan"           , p_vlan_port_db->pkt_cvlan);
        CTC_APP_DBG_DUMP("%-40s : %10u\n" , "egress_policer_id"  , p_vlan_port_db->egress_policer_id);
    }

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_show_status(uint8 lchip)
{
    uint16 vdev_index = 0;

    CTC_APP_DBG_DUMP("%-40s : %u\n", "Mcast tunnel Value logic port",  p_app_pon_master->bcast_value_logic_port);
    for (vdev_index=0; vdev_index<p_app_pon_master->vdev_num; vdev_index++)
    {
        CTC_APP_DBG_DUMP("vDev ID:%u\n", vdev_index);
        CTC_APP_DBG_DUMP("---------------------------------------------------------------------------------------------\n");
        CTC_APP_DBG_DUMP("%-40s : %u\n", "gem port",    p_app_pon_master->gem_port_cnt[vdev_index]);
        CTC_APP_DBG_DUMP("%-40s : %u\n", "vlan port",   p_app_pon_master->vlan_port_cnt[vdev_index]);
        CTC_APP_DBG_DUMP("%-40s : %u\n", "nni port",    p_app_pon_master->nni_port_cnt[vdev_index]);

        CTC_APP_DBG_DUMP("\n");
        CTC_APP_DBG_DUMP("Resource:\n");
        CTC_APP_DBG_DUMP("---------------------------------------------------------------------------------------------\n");
        CTC_APP_DBG_DUMP("%-40s : %u\n", "default bcast fid",           p_app_pon_master->default_bcast_fid[vdev_index]);
        CTC_APP_DBG_DUMP("%-40s : %u\n", "nni mcast nhid",              p_app_pon_master->nni_mcast_nhid[vdev_index]);
        CTC_APP_DBG_DUMP("%-40s : %u\n", "default mcast group id",      p_app_pon_master->default_mcast_group_id[vdev_index]);
        CTC_APP_DBG_DUMP("%-40s : %u\n", "default unknown mcast nhid",  p_app_pon_master->default_unknown_mcast_nhid[vdev_index]);
        CTC_APP_DBG_DUMP("%-40s : %u\n", "default unknown bcast nhid",  p_app_pon_master->default_unknown_bcast_nhid[vdev_index]);
    }

    return CTC_E_NONE;
}

#define CTC_APP_PON_DUMP(param) CTC_APP_DBG_DUMP("%-40s :%10u\n", #param, vlan_port.param)
int32
ctc_app_pon_show_logic_port(uint8 lchip, uint32 logic_port)
{
    ctc_app_pon_service_t vlan_port;

    CTC_APP_PON_INIT_CHECK();

    sal_memset(&vlan_port, 0, sizeof(vlan_port));

    CTC_APP_PON_LOCK(lchip);
    CTC_ERROR_RETURN_APP_PON_UNLOCK(ctc_app_pon_get_by_logic_port(lchip, logic_port, &vlan_port));
    CTC_APP_PON_UNLOCK(lchip);

    CTC_APP_DBG_DUMP("logic port: %u detail:\n", logic_port);
    CTC_APP_DBG_DUMP("---------------------------------------------------------------------------------------------\n");
    CTC_APP_PON_DUMP(vlan_port_id);
    CTC_APP_PON_DUMP(criteria);
    CTC_APP_DBG_DUMP("%-40s :%10u\n", "port", vlan_port.port);
    CTC_APP_PON_DUMP(match_tunnel_value);
    CTC_APP_PON_DUMP(match_svlan);
    CTC_APP_PON_DUMP(match_cvlan);
    CTC_APP_PON_DUMP(match_svlan_end);
    CTC_APP_PON_DUMP(match_cvlan_end);

    CTC_APP_PON_DUMP(ingress_vlan_action_set.svid);
    CTC_APP_PON_DUMP(ingress_vlan_action_set.new_svid);
    CTC_APP_PON_DUMP(ingress_vlan_action_set.cvid);
    CTC_APP_PON_DUMP(ingress_vlan_action_set.new_cvid);
    CTC_APP_PON_DUMP(ingress_vlan_action_set.scos);
    CTC_APP_PON_DUMP(ingress_vlan_action_set.new_scos);
    CTC_APP_PON_DUMP(ingress_vlan_action_set.ccos);
    CTC_APP_PON_DUMP(ingress_vlan_action_set.new_ccos);

    CTC_APP_PON_DUMP(egress_vlan_action_set.svid);
    CTC_APP_PON_DUMP(egress_vlan_action_set.new_svid);
    CTC_APP_PON_DUMP(egress_vlan_action_set.cvid);
    CTC_APP_PON_DUMP(egress_vlan_action_set.new_cvid);
    CTC_APP_PON_DUMP(egress_vlan_action_set.scos);
    CTC_APP_PON_DUMP(egress_vlan_action_set.new_scos);
    CTC_APP_PON_DUMP(egress_vlan_action_set.ccos);
    CTC_APP_PON_DUMP(egress_vlan_action_set.new_ccos);

    return CTC_E_NONE;
}

int32
ctc_app_pon_show(uint8 lchip, uint8 type, uint8 detail, uint32 param0, uint32 param1)
{
    int32 ret = CTC_E_NONE;

    CTC_APP_PON_INIT_CHECK();

    CTC_APP_PON_LOCK(lchip);
    switch(type)
    {
        case 0:
            ret = _ctc_app_pon_show_status(lchip);
            break;
        case 1:
            ret = _ctc_app_pon_show_uni_port(lchip, detail, param0);
            break;
        case 2:
            ret = _ctc_app_pon_show_gem_port(lchip, detail, param0, param1);
            break;
        case 3:
            ret = _ctc_app_pon_show_vlan_port(lchip, detail, param0);
            break;
        case 4:
            ret = _ctc_app_pon_show_nni_port(lchip, param0);
            break;

        default:
           break;
    }
    CTC_APP_PON_UNLOCK(lchip);

    return ret;
}

STATIC int32
_ctc_app_pon_show_fid(void* node, void* user_data)
{
    ctc_app_pon_fid_db_t* p_port_fid_db = (ctc_app_pon_fid_db_t*)(((ctc_spool_node_t*)node)->data);
    ctc_app_pon_fid_db_t* p_port_fid_db_temp = (ctc_app_pon_fid_db_t*)user_data;

    if (p_port_fid_db_temp->vdev_id == p_port_fid_db->vdev_id)
    {
        CTC_APP_DBG_DUMP("%-10u %10u %10u %10u %10u\n",
              p_port_fid_db_temp->fid,
              p_port_fid_db->vdev_id,
              p_port_fid_db->pkt_svlan,
              p_port_fid_db->pkt_cvlan,
              p_port_fid_db->fid
             );
        p_port_fid_db_temp->fid++;
    }
    return CTC_E_NONE;
}

int32
ctc_app_pon_show_fid(uint8 lchip, uint16 vdev_id)
{
    ctc_app_pon_fid_db_t port_fid_db;
    CTC_APP_PON_INIT_CHECK();
    CTC_APP_PON_VDEV_ID_CHECK(vdev_id);

    sal_memset(&port_fid_db, 0, sizeof(port_fid_db));
    port_fid_db.vdev_id = vdev_id;
    CTC_APP_PON_LOCK(lchip);

    CTC_APP_DBG_DUMP("%-10s %10s %10s %10s %10s\n", "index", "vDev id", "Packet svlan", "Packet cvlan", "fid");
    CTC_APP_DBG_DUMP("---------------------------------------------------------------\n");

    ctc_spool_traverse(p_app_pon_master->fid_spool,
                      (spool_traversal_fn)_ctc_app_pon_show_fid, &port_fid_db);

    CTC_APP_DBG_DUMP("VLan mapping fid db: %u\n", port_fid_db.fid);
    CTC_APP_PON_UNLOCK(lchip);

    return CTC_E_NONE;
}

#define _____GLOBAL_PROPERTY_____ ""
#if 0
int32
_ctc_app_pon_set_xc_port_discard(uint8 lchip, uint32 src_gport, uint32 dst_gport, uint8 discard)
{
    int32 ret = 0;
    ctc_port_scl_property_t scl_prop;
    ctc_scl_entry_t  scl_entry;

    if (discard)
    {
        sal_memset(&scl_entry, 0, sizeof(scl_entry));
        ctc_field_key_t field_key;
        ctc_field_port_t field_port;
        ctc_scl_field_action_t field_action;
        scl_entry.key_type = CTC_SCL_KEY_HASH_PORT_CROSS;
        scl_entry.mode = 1;
        scl_entry.action_type =  CTC_SCL_ACTION_EGRESS;
        scl_entry.entry_id = ENCODE_SCL_XC_ENTRY_ID(src_gport*100 + dst_gport);
        CTC_ERROR_GOTO(ctc_scl_add_entry(CTC_SCL_GROUP_ID_HASH_PORT_IPV4, &scl_entry), ret, roll_back_0);
        sal_memset(&field_key, 0, sizeof(ctc_field_key_t));
        sal_memset(&field_port, 0, sizeof(ctc_field_port_t));
        field_key.type = CTC_FIELD_KEY_PORT;
        field_port.gport = src_gport;
        field_port.type = CTC_FIELD_PORT_TYPE_GPORT;
        field_key.ext_data = &field_port;
        CTC_ERROR_GOTO(ctc_scl_add_key_field(scl_entry.entry_id, &field_key), ret, roll_back_1);
        sal_memset(&field_key, 0, sizeof(ctc_field_key_t));
        sal_memset(&field_port, 0, sizeof(ctc_field_port_t));
        field_key.type = CTC_FIELD_KEY_DST_GPORT;
        field_port.type = CTC_FIELD_PORT_TYPE_GPORT;
        field_port.gport = dst_gport;
        field_key.ext_data = &field_port;
        CTC_ERROR_GOTO(ctc_scl_add_key_field(scl_entry.entry_id, &field_key), ret, roll_back_1);
        sal_memset(&field_key, 0, sizeof(ctc_field_key_t));
        field_key.type = CTC_FIELD_KEY_HASH_VALID;
        CTC_ERROR_GOTO(ctc_scl_add_key_field(scl_entry.entry_id, &field_key), ret, roll_back_1);
        sal_memset(&field_action, 0, sizeof(ctc_scl_field_action_t));
        field_action.type = CTC_SCL_FIELD_ACTION_TYPE_DROP_UNKNOWN_UCAST;
        CTC_ERROR_GOTO(ctc_scl_add_action_field(scl_entry.entry_id, &field_action), ret, roll_back_1);
        field_action.type = CTC_SCL_FIELD_ACTION_TYPE_DROP_UNKNOWN_MCAST;
        CTC_ERROR_GOTO(ctc_scl_add_action_field(scl_entry.entry_id, &field_action), ret, roll_back_1);
        field_action.type = CTC_SCL_FIELD_ACTION_TYPE_DROP_BCAST;
        CTC_ERROR_GOTO(ctc_scl_add_action_field(scl_entry.entry_id, &field_action), ret, roll_back_1);
        field_action.type = CTC_SCL_FIELD_ACTION_TYPE_DROP_KNOWN_UCAST;
        CTC_ERROR_GOTO(ctc_scl_add_action_field(scl_entry.entry_id, &field_action), ret, roll_back_1);
        field_action.type = CTC_SCL_FIELD_ACTION_TYPE_DROP_KNOWN_MCAST;
        CTC_ERROR_GOTO(ctc_scl_add_action_field(scl_entry.entry_id, &field_action), ret, roll_back_1);
        CTC_ERROR_GOTO(ctc_scl_install_entry(scl_entry.entry_id), ret, roll_back_1);

        sal_memset(&scl_prop, 0, sizeof(scl_prop));
        scl_prop.scl_id = 1;
        scl_prop.direction = CTC_EGRESS;
        scl_prop.hash_type = CTC_PORT_EGS_SCL_HASH_TYPE_PORT_XC;
        scl_prop.action_type = CTC_PORT_SCL_ACTION_TYPE_SCL;
        CTC_ERROR_GOTO(ctc_port_set_scl_property(dst_gport, &scl_prop), ret, roll_back_2);
    }
    else
    {
        sal_memset(&scl_entry, 0, sizeof(scl_entry));
        scl_entry.entry_id = ENCODE_SCL_XC_ENTRY_ID(src_gport*100 + dst_gport);
        CTC_APP_DBG_INFO("EntryId :%u\n", scl_entry.entry_id );
        CTC_ERROR_GOTO(ctc_scl_uninstall_entry(scl_entry.entry_id), ret, roll_back_0);
        CTC_ERROR_GOTO(ctc_scl_remove_entry(scl_entry.entry_id), ret, roll_back_0);
        sal_memset(&scl_prop, 0, sizeof(scl_prop));
        scl_prop.scl_id = 1;
        scl_prop.direction = CTC_EGRESS;
        scl_prop.hash_type = CTC_PORT_EGS_SCL_HASH_TYPE_DISABLE;
        CTC_ERROR_GOTO(ctc_port_set_scl_property(dst_gport, &scl_prop), ret, roll_back_0);
    }

    return CTC_E_NONE;

roll_back_2:
    ctc_scl_uninstall_entry(scl_entry.entry_id);

roll_back_1:
    ctc_scl_remove_entry(scl_entry.entry_id);
roll_back_0:

    return ret;
}
#endif
int32
_ctc_app_pon_set_uni_inner_isolate(uint8 lchip, ctc_app_pon_global_cfg_t* p_glb_cfg)
{
    uint8 gchip = 0;
    uint32 lport = 0;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;
    uint8 discard = 0;
    uint32 gport = 0;

    CTC_ERROR_RETURN(ctc_get_gchip_id(lchip, &gchip));

    discard = p_glb_cfg->value?1:0;

    if (p_app_pon_master->uni_inner_isolate_en[p_glb_cfg->vdev_id] == discard)
    {
        return CTC_E_NONE;
    }

    for (lport = 0; lport < 128; lport++)
    {
        p_uni_port = &p_app_pon_master->p_port_pon[lport];

        if (p_uni_port->vdev_id != p_glb_cfg->vdev_id)
        {
            continue;
        }
        gport = CTC_MAP_LPORT_TO_GPORT(gchip, lport);
        CTC_APP_DBG_PARAM("%-40s :%10u\n", "gport", gport);
        CTC_ERROR_RETURN(ctc_port_set_reflective_bridge_en(gport, !discard));
    }

    p_app_pon_master->uni_inner_isolate_en[p_glb_cfg->vdev_id] = discard;

    return CTC_E_NONE;
}

int32
_ctc_app_pon_set_uni_outer_isolate(uint8 lchip, ctc_app_pon_global_cfg_t* p_glb_cfg)
{
    uint8 gchip = 0;
    uint32 lport = 0;
    ctc_port_restriction_t isolation;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;
    uint8 discard = 0;

    ctc_get_gchip_id(lchip, &gchip);

    discard = p_glb_cfg->value?1:0;

    if (p_app_pon_master->uni_outer_isolate_en[p_glb_cfg->vdev_id] == discard)
    {
        return CTC_E_NONE;
    }

    for (lport = 0; lport < 128; lport++)
    {
        p_uni_port = &p_app_pon_master->p_port_pon[lport];

        if ((0 == p_uni_port->isolated_id) || (p_uni_port->vdev_id != p_glb_cfg->vdev_id))
        {
            continue;
        }

        /***********************************************/
        /** PORT ISOLATION*/
        sal_memset(&isolation, 0, sizeof(isolation));
        isolation.dir = CTC_EGRESS;
        isolation.isolated_id = p_glb_cfg->value? p_uni_port->isolated_id: 0;
        isolation.mode = p_glb_cfg->value? CTC_PORT_RESTRICTION_PORT_ISOLATION: CTC_PORT_RESTRICTION_DISABLE;
        isolation.type = CTC_PORT_ISOLATION_ALL;
        CTC_ERROR_RETURN(ctc_port_set_restriction(CTC_MAP_LPORT_TO_GPORT(gchip, lport), &isolation));
        isolation.dir = CTC_INGRESS;
        CTC_ERROR_RETURN(ctc_port_set_restriction(CTC_MAP_LPORT_TO_GPORT(gchip, lport), &isolation));
    }

    p_app_pon_master->uni_outer_isolate_en[p_glb_cfg->vdev_id] = discard;

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_set_unknown_mcast_drop(uint8 lchip, ctc_app_pon_global_cfg_t* p_glb_cfg)
{
    uint8 drop_en  = 0;
    uint16 lport = 0;
    uint32 mcast_group_id = 0;
    uint32 mcast_group_nh_id = 0;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;
    ctc_mcast_nh_param_group_t mcast_group;

    drop_en = p_glb_cfg->value?1:0;

    if (p_app_pon_master->unknown_mcast_drop_en[p_glb_cfg->vdev_id] == drop_en)
    {
        return CTC_E_NONE;
    }

    for (lport = 0; lport < 128; lport++)
    {
        p_uni_port = &p_app_pon_master->p_port_pon[lport];

        if ((0 == p_uni_port->isolated_id) || (p_uni_port->vdev_id != p_glb_cfg->vdev_id))
        {
            continue;
        }

        mcast_group_id = ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[p_glb_cfg->vdev_id], 3);
        mcast_group_nh_id = p_app_pon_master->default_unknown_mcast_nhid[p_glb_cfg->vdev_id];


        /*Add or remove MC member(drop_en: 0-add, others-remove)*/
        sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
        mcast_group.mc_grp_id = mcast_group_id;
        mcast_group.opcode = drop_en? CTC_NH_PARAM_MCAST_DEL_MEMBER: CTC_NH_PARAM_MCAST_ADD_MEMBER;
        mcast_group.mem_info.ref_nhid = p_uni_port->mc_xlate_nhid;
        mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
        CTC_ERROR_RETURN(ctc_nh_update_mcast(mcast_group_nh_id, &mcast_group));

        mcast_group_nh_id = p_app_pon_master->glb_unknown_mcast_nhid;
        ctc_nh_update_mcast(mcast_group_nh_id, &mcast_group);
    }

    p_app_pon_master->unknown_mcast_drop_en[p_glb_cfg->vdev_id] = drop_en;

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_set_mac_learn_limit(uint8 lchip, ctc_app_pon_global_cfg_t* p_glb_cfg)
{
    int32 ret = CTC_E_NONE;
    ctc_app_pon_mac_learn_limit_t* p_mac_learn = NULL;
    ctc_security_learn_limit_t learn_limit;
    ctc_app_pon_gem_port_db_t gem_port_db;
    ctc_app_pon_gem_port_db_t* p_gem_port_db = NULL;
    ctc_app_pon_fid_db_t port_fid_db;
    ctc_app_pon_fid_db_t* p_port_fid_db = NULL;
    ctc_pon_gem_port_t gem_port;

    sal_memset(&learn_limit, 0, sizeof(ctc_security_learn_limit_t));
    p_mac_learn = &p_glb_cfg->mac_learn;
    switch(p_mac_learn->limit_type)
    {
        case CTC_APP_PON_MAC_LEARN_LIMIT_TYPE_SYSTEM:
            learn_limit.limit_action = p_mac_learn->limit_action;
            learn_limit.limit_type = CTC_SECURITY_LEARN_LIMIT_TYPE_SYSTEM;
            learn_limit.limit_num = p_mac_learn->limit_num;
            CTC_ERROR_RETURN(ctc_mac_security_set_learn_limit(&learn_limit));
            break;
        case CTC_APP_PON_MAC_LEARN_LIMIT_TYPE_VDEV:
            if (p_mac_learn->limit_action == CTC_MACLIMIT_ACTION_TOCPU)
            {
                return CTC_E_INVALID_PARAM;
            }

            if ((p_mac_learn->limit_num == CTC_APP_PON_LIMIT_NUM_DISABLE)
                && (p_app_pon_master->limit_num[p_glb_cfg->vdev_id] != CTC_APP_PON_LIMIT_NUM_DISABLE))
            {
                _ctc_app_pon_traverse_fid(CTC_MACLIMIT_ACTION_NONE, p_glb_cfg->vdev_id);
            }
            else if ((p_mac_learn->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE)
                && (p_app_pon_master->limit_num[p_glb_cfg->vdev_id] != CTC_APP_PON_LIMIT_NUM_DISABLE)
                && (p_app_pon_master->limit_action[p_glb_cfg->vdev_id] != p_mac_learn->limit_action))
            {
                return CTC_E_NOT_SUPPORT;
            }

            if (0 == p_mac_learn->limit_num)
            {
                _ctc_app_pon_traverse_fid(p_mac_learn->limit_action, p_glb_cfg->vdev_id);
            }

            p_app_pon_master->limit_num[p_glb_cfg->vdev_id] = p_mac_learn->limit_num;
            p_app_pon_master->limit_action[p_glb_cfg->vdev_id] = p_mac_learn->limit_action;
            break;
        case CTC_APP_PON_MAC_LEARN_LIMIT_TYPE_FID:
            sal_memset(&port_fid_db, 0, sizeof(ctc_app_pon_fid_db_t));
            port_fid_db.fid = p_mac_learn->fid;
            ret = _ctc_app_pon_get_fid_by_fid(&port_fid_db);
            if (!ret)
            {
                return CTC_E_NOT_EXIST;
            }

            p_port_fid_db = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
            if (NULL == p_port_fid_db)
            {
                return CTC_E_NOT_EXIST;
            }

            if ((p_mac_learn->limit_num == CTC_APP_PON_LIMIT_NUM_DISABLE)
                && (p_port_fid_db->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE))
            {
                ctc_l2_set_fid_property(p_port_fid_db->fid, CTC_L2_FID_PROP_MAC_LIMIT_ACTION, CTC_MACLIMIT_ACTION_NONE);
            }
            else if ((p_mac_learn->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE)
                && (p_port_fid_db->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE)
                && (p_port_fid_db->limit_action != p_mac_learn->limit_action))
            {
                return CTC_E_NOT_SUPPORT;
            }

            if (0 == p_mac_learn->limit_num)
            {
                ctc_l2_set_fid_property(p_port_fid_db->fid, CTC_L2_FID_PROP_MAC_LIMIT_ACTION, p_mac_learn->limit_action);
            }
            p_port_fid_db->limit_action = p_mac_learn->limit_action;
            p_port_fid_db->limit_num = p_mac_learn->limit_num;
            break;
        case CTC_APP_PON_MAC_LEARN_LIMIT_TYPE_GEM_PORT:
            sal_memset(&gem_port, 0, sizeof(gem_port));
            gem_port.gport = p_mac_learn->gport;
            gem_port.tunnel_value = p_mac_learn->tunnel_value;
            CTC_ERROR_RETURN(ctc_pon_get_gem_port(&gem_port));
            sal_memset(&gem_port_db, 0, sizeof(gem_port_db));
            gem_port_db.port = p_mac_learn->gport;
            gem_port_db.tunnel_value = p_mac_learn->tunnel_value;
            p_gem_port_db = ctc_hash_lookup(p_app_pon_master->gem_port_hash, &gem_port_db);
            if (NULL == p_gem_port_db)
            {
                return CTC_E_NOT_EXIST;
            }

            if ((p_mac_learn->limit_num == CTC_APP_PON_LIMIT_NUM_DISABLE)
                && (p_gem_port_db->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE))
            {
                gem_port.limit_action = CTC_MACLIMIT_ACTION_NONE;
                p_gem_port_db->mac_security = CTC_MACLIMIT_ACTION_NONE;
            }
            else if ((p_mac_learn->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE)
                && (p_gem_port_db->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE)
                && (p_gem_port_db->limit_action != p_mac_learn->limit_action))
            {
                return CTC_E_NOT_SUPPORT;
            }

            if ((0 == p_mac_learn->limit_num) && (p_mac_learn->limit_action == CTC_MACLIMIT_ACTION_DISCARD))
            {
                gem_port.limit_action = CTC_MACLIMIT_ACTION_DISCARD;
                p_gem_port_db->mac_security = CTC_MACLIMIT_ACTION_DISCARD;
            }
            else if ((0 == p_mac_learn->limit_num) && (p_mac_learn->limit_action == CTC_MACLIMIT_ACTION_TOCPU))
            {
                gem_port.limit_action = CTC_MACLIMIT_ACTION_TOCPU;
                p_gem_port_db->mac_security = CTC_MACLIMIT_ACTION_TOCPU;
            }
            CTC_SET_FLAG(gem_port.flag, CTC_PON_GEM_PORT_FLAG_MAC_LIMIT);
            CTC_ERROR_RETURN(ctc_pon_update_gem_port(&gem_port));
            p_gem_port_db->limit_action = p_mac_learn->limit_action;
            p_gem_port_db->limit_num = p_mac_learn->limit_num;
            break;
        default:
            break;
    }

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_fid_compare_svlan(void* node, void* user_data)
{
    ctc_app_pon_fid_db_t* p_port_fid = (ctc_app_pon_fid_db_t*)(((ctc_spool_node_t*)node)->data);
    uint16 svlan = *(uint16*)user_data;

    if (p_port_fid->pkt_svlan == svlan)
    {
        return CTC_E_EXIST;
    }

    return CTC_E_NONE;
}

int32
_ctc_app_pon_traverse_fid_with_svlan(uint16 svlan)
{

    CTC_ERROR_RETURN(ctc_spool_traverse(p_app_pon_master->fid_spool,
                          (spool_traversal_fn)_ctc_app_pon_fid_compare_svlan, &svlan));

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_set_vlan_glb_vdev_en(uint8 lchip, ctc_app_pon_global_cfg_t* p_glb_cfg)
{
    int32 ret = CTC_E_NONE;
    uint16 vlan_id = 0;

    CTC_VLAN_RANGE_CHECK(p_glb_cfg->vlan_id);
    vlan_id = p_glb_cfg->vlan_id;

    ret = _ctc_app_pon_traverse_fid_with_svlan(vlan_id);
    if (ret)
    {
        return CTC_E_EXIST;
    }

    if (p_glb_cfg->value)
    {
        CTC_BIT_SET(p_app_pon_master->vlan_glb_vdev[vlan_id/32], vlan_id%32);
    }
    else
    {
        CTC_BIT_UNSET(p_app_pon_master->vlan_glb_vdev[vlan_id/32], vlan_id%32);
    }

    return CTC_E_NONE;
}

int32
ctc_app_pon_set_global_cfg(uint8 lchip, ctc_app_pon_global_cfg_t* p_glb_cfg)
{
    CTC_PTR_VALID_CHECK(p_glb_cfg);
    CTC_APP_PON_INIT_CHECK();
    CTC_APP_PON_VDEV_ID_CHECK(p_glb_cfg->vdev_id);

    CTC_APP_PON_LOCK(lchip);
    switch(p_glb_cfg->cfg_type)
    {
    case CTC_APP_VLAN_CFG_UNI_OUTER_ISOLATE:
        CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_set_uni_outer_isolate(lchip, p_glb_cfg));
        break;

    case CTC_APP_VLAN_CFG_UNI_INNER_ISOLATE:
        CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_set_uni_inner_isolate(lchip, p_glb_cfg));
        break;

    case CTC_APP_VLAN_CFG_UNKNOWN_MCAST_DROP:
        CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_set_unknown_mcast_drop(lchip, p_glb_cfg));
        break;

    case CTC_APP_VLAN_CFG_MAC_LEARN_LIMIT:
        CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_set_mac_learn_limit(lchip, p_glb_cfg));
        break;

    case CTC_APP_VLAN_CFG_VLAN_GLOBAL_VDEV_EN:
        CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_set_vlan_glb_vdev_en(lchip, p_glb_cfg));
        break;

    default:
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_INVALID_CONFIG;
    }
    CTC_APP_PON_UNLOCK(lchip);

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_get_mac_learn_limit(uint8 lchip, ctc_app_pon_global_cfg_t* p_glb_cfg)
{
    int32 ret = CTC_E_NONE;
    ctc_app_pon_mac_learn_limit_t* p_mac_learn = NULL;
    ctc_security_learn_limit_t learn_limit;
    ctc_app_pon_gem_port_db_t gem_port_db;
    ctc_app_pon_gem_port_db_t* p_gem_port_db = NULL;
    ctc_app_pon_fid_db_t port_fid_db;
    ctc_app_pon_fid_db_t* p_port_fid_db = NULL;

    sal_memset(&learn_limit, 0, sizeof(ctc_security_learn_limit_t));
    p_mac_learn = &p_glb_cfg->mac_learn;
    switch(p_mac_learn->limit_type)
    {
        case CTC_APP_PON_MAC_LEARN_LIMIT_TYPE_SYSTEM:
            learn_limit.limit_action = p_mac_learn->limit_action;
            learn_limit.limit_type = CTC_SECURITY_LEARN_LIMIT_TYPE_SYSTEM;
            learn_limit.limit_num = p_mac_learn->limit_num;
            ctc_mac_security_get_learn_limit(&learn_limit);

            p_mac_learn->limit_count = learn_limit.limit_count;
            p_mac_learn->limit_num = learn_limit.limit_num;
            p_mac_learn->limit_action = learn_limit.limit_action;
            break;
        case CTC_APP_PON_MAC_LEARN_LIMIT_TYPE_VDEV:
            p_mac_learn->limit_count = p_app_pon_master->limit_count[p_glb_cfg->vdev_id];
            p_mac_learn->limit_num = p_app_pon_master->limit_num[p_glb_cfg->vdev_id];
            p_mac_learn->limit_action = p_app_pon_master->limit_action[p_glb_cfg->vdev_id];
            break;
        case CTC_APP_PON_MAC_LEARN_LIMIT_TYPE_FID:
            sal_memset(&port_fid_db, 0, sizeof(ctc_app_pon_fid_db_t));
            port_fid_db.fid = p_mac_learn->fid;
            ret = _ctc_app_pon_get_fid_by_fid(&port_fid_db);
            if (!ret)
            {
                return CTC_E_NOT_EXIST;
            }

            p_port_fid_db = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
            if (NULL == p_port_fid_db)
            {
                return CTC_E_NOT_EXIST;
            }
            p_mac_learn->limit_count = p_port_fid_db->limit_count;
            p_mac_learn->limit_num = p_port_fid_db->limit_num;
            p_mac_learn->limit_action = p_port_fid_db->limit_action;
            break;
        case CTC_APP_PON_MAC_LEARN_LIMIT_TYPE_GEM_PORT:
            sal_memset(&gem_port_db, 0, sizeof(gem_port_db));
            gem_port_db.port = p_mac_learn->gport;
            gem_port_db.tunnel_value = p_mac_learn->tunnel_value;
            p_gem_port_db = ctc_hash_lookup(p_app_pon_master->gem_port_hash, &gem_port_db);
            if (NULL == p_gem_port_db)
            {
                return CTC_E_NOT_EXIST;
            }

            p_mac_learn->limit_count = p_gem_port_db->limit_count;
            p_mac_learn->limit_num = p_gem_port_db->limit_num;
            p_mac_learn->limit_action = p_gem_port_db->limit_action;
            break;
        default:
            break;
    }

    return CTC_E_NONE;
}

int32
ctc_app_pon_get_global_cfg(uint8 lchip, ctc_app_pon_global_cfg_t* p_glb_cfg)
{
    uint16 vlan_id = 0;

    CTC_PTR_VALID_CHECK(p_glb_cfg);
    CTC_APP_PON_INIT_CHECK();
    CTC_APP_PON_VDEV_ID_CHECK(p_glb_cfg->vdev_id);

    if (p_glb_cfg->cfg_type == CTC_APP_VLAN_CFG_VLAN_GLOBAL_VDEV_EN)
    {
        CTC_VLAN_RANGE_CHECK(p_glb_cfg->vlan_id);
    }

    CTC_APP_PON_LOCK(lchip);
    switch(p_glb_cfg->cfg_type)
    {
        case CTC_APP_VLAN_CFG_UNI_OUTER_ISOLATE:
            p_glb_cfg->value = p_app_pon_master->uni_outer_isolate_en[p_glb_cfg->vdev_id];
            break;

        case CTC_APP_VLAN_CFG_UNI_INNER_ISOLATE:
            p_glb_cfg->value = p_app_pon_master->uni_inner_isolate_en[p_glb_cfg->vdev_id];
            break;

        case CTC_APP_VLAN_CFG_UNKNOWN_MCAST_DROP:
            p_glb_cfg->value = p_app_pon_master->unknown_mcast_drop_en[p_glb_cfg->vdev_id];
            break;
        case CTC_APP_VLAN_CFG_MAC_LEARN_LIMIT:
            CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_get_mac_learn_limit(lchip, p_glb_cfg));
            break;

        case CTC_APP_VLAN_CFG_VLAN_GLOBAL_VDEV_EN:
            vlan_id = p_glb_cfg->vlan_id;
            p_glb_cfg->value = CTC_IS_BIT_SET(p_app_pon_master->vlan_glb_vdev[vlan_id/32], vlan_id%32);
            break;

        default:
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_INVALID_CONFIG;
    }
    CTC_APP_PON_UNLOCK(lchip);

    return CTC_E_NONE;
}


#define _____VLAN_PORT_____ ""

STATIC int32
_ctc_app_pon_vlan_edit(uint8 lchip, ctc_app_pon_service_t* p_vlan_port,
                                uint16* pkt_svid,
                                uint16* pkt_cvid)
{
    CTC_APP_PON_INIT_CHECK();

    if (CTC_APP_PON_VLAN_ACTION_ADD == p_vlan_port->ingress_vlan_action_set.svid)
    {
        if(CTC_APP_PON_VLAN_ACTION_ADD == p_vlan_port->ingress_vlan_action_set.cvid)
        {
            *pkt_svid = p_vlan_port->ingress_vlan_action_set.new_svid;
            *pkt_cvid = p_vlan_port->ingress_vlan_action_set.new_cvid;
        }
        else
        {
            *pkt_svid = p_vlan_port->ingress_vlan_action_set.new_svid;
            if (p_vlan_port->match_svlan_end)
            {
                *pkt_cvid = p_vlan_port->match_svlan_end;
            }
            else
            {
                *pkt_cvid = p_vlan_port->match_svlan;
            }
        }
    }
    else if(CTC_APP_PON_VLAN_ACTION_REPLACE == p_vlan_port->ingress_vlan_action_set.svid)
    {
        if ((CTC_APP_PON_VLAN_ACTION_ADD == p_vlan_port->ingress_vlan_action_set.cvid) || \
            (CTC_APP_PON_VLAN_ACTION_REPLACE == p_vlan_port->ingress_vlan_action_set.cvid))
        {
            *pkt_svid = p_vlan_port->ingress_vlan_action_set.new_svid;
            *pkt_cvid = p_vlan_port->ingress_vlan_action_set.new_cvid;
        }
        else
        {
            *pkt_svid = p_vlan_port->ingress_vlan_action_set.new_svid;
            *pkt_cvid = p_vlan_port->match_cvlan;
        }
    }
    else if(CTC_APP_PON_VLAN_ACTION_NONE == p_vlan_port->ingress_vlan_action_set.svid)
    {
        if ((CTC_APP_PON_VLAN_ACTION_ADD == p_vlan_port->ingress_vlan_action_set.cvid) || \
            (CTC_APP_PON_VLAN_ACTION_REPLACE == p_vlan_port->ingress_vlan_action_set.cvid))
        {
            *pkt_svid = p_vlan_port->match_svlan;
            *pkt_cvid = p_vlan_port->ingress_vlan_action_set.new_cvid;
        }
        else
        {
            *pkt_svid = p_vlan_port->match_svlan;
            *pkt_cvid = p_vlan_port->match_cvlan;
        }
    }

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_remove_vlan(uint8 lchip,
                           ctc_app_pon_service_t* p_vlan_port,
                           ctc_app_pon_db_t* p_vlan_port_db)
{
    ctc_l2dflt_addr_t l2dflt;
    ctc_app_pon_gem_port_db_t* p_gem_port_db = NULL;
    ctc_mcast_nh_param_group_t mcast_group;
    uint16 mcast_group_id = 0;
    uint32 nh_id = 0;

    p_gem_port_db = p_vlan_port_db->p_gem_port_db;

    /*Add vlan member*/
    if (NULL != p_gem_port_db)
    {
        sal_memset(&l2dflt, 0, sizeof(l2dflt));
        l2dflt.fid = p_vlan_port_db->fid;
        l2dflt.l2mc_grp_id = p_vlan_port_db->fid;
        l2dflt.with_nh = 1;

        l2dflt.logic_port = p_vlan_port_db->logic_port;
        l2dflt.member.nh_id = p_vlan_port_db->xlate_nhid;
        ctc_l2_remove_port_from_default_entry(&l2dflt);

        if(p_app_pon_master->mcast_tunnel_vlan == 0xffff)
        {
            sal_memset(&l2dflt, 0, sizeof(l2dflt));
            l2dflt.fid = p_vlan_port_db->fid;
            ctc_l2_get_default_entry_features(&l2dflt);
            mcast_group_id = ENCODE_MCAST_GROUP_ID(l2dflt.l2mc_grp_id, 1);
            ctc_nh_get_mcast_nh(mcast_group_id, &nh_id);
            sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
            mcast_group.mc_grp_id = mcast_group_id;
            mcast_group.opcode = CTC_NH_PARAM_MCAST_DEL_MEMBER;
            mcast_group.mem_info.ref_nhid = p_vlan_port_db->xlate_nhid;
            mcast_group.mem_info.logic_dest_port = p_vlan_port_db->logic_port;
            mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
            ctc_nh_update_mcast(nh_id, &mcast_group);
        }

        CTC_APP_DBG_INFO("Group(%u) remove ONU nhid: %u\n", l2dflt.l2mc_grp_id, l2dflt.member.nh_id);
    }

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_add_vlan(uint8 lchip,
                           ctc_app_pon_service_t* p_vlan_port,
                           ctc_app_pon_db_t* p_vlan_port_db)
{
    ctc_l2dflt_addr_t l2dflt;
    ctc_app_pon_gem_port_db_t* p_gem_port_db = NULL;
    ctc_mcast_nh_param_group_t mcast_group;
    uint16 mcast_group_id = 0;
    uint32 nh_id = 0;
    int32 ret = CTC_E_NONE;

    p_gem_port_db = p_vlan_port_db->p_gem_port_db;

    /*Add vlan member*/
    if (NULL != p_gem_port_db)
    {
        sal_memset(&l2dflt, 0, sizeof(l2dflt));
        l2dflt.fid = p_vlan_port_db->fid;
        l2dflt.l2mc_grp_id = p_vlan_port_db->fid;
        l2dflt.with_nh = 1;

        l2dflt.logic_port = p_vlan_port_db->logic_port;
        l2dflt.member.nh_id = p_vlan_port_db->xlate_nhid;
        CTC_ERROR_RETURN(ctc_l2_add_port_to_default_entry(&l2dflt));


        CTC_APP_DBG_INFO("Group(%u) add ONU nhid: %u\n", l2dflt.l2mc_grp_id, l2dflt.member.nh_id);

        if(p_app_pon_master->mcast_tunnel_vlan == 0xffff)
        {
            sal_memset(&l2dflt, 0, sizeof(l2dflt));
            l2dflt.fid = p_vlan_port_db->fid;
            ctc_l2_get_default_entry_features(&l2dflt);
            mcast_group_id = ENCODE_MCAST_GROUP_ID(l2dflt.l2mc_grp_id, 1);
            ctc_nh_get_mcast_nh(mcast_group_id, &nh_id);
            sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
            mcast_group.mc_grp_id = mcast_group_id;
            mcast_group.opcode = CTC_NH_PARAM_MCAST_ADD_MEMBER;
            mcast_group.mem_info.ref_nhid = p_vlan_port_db->xlate_nhid;
            mcast_group.mem_info.logic_dest_port = p_vlan_port_db->logic_port;
            mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
            CTC_ERROR_GOTO(ctc_nh_update_mcast( nh_id, &mcast_group), ret, roll_back_0);
        }
    }

    return CTC_E_NONE;
roll_back_0:
    _ctc_app_pon_remove_vlan(lchip, p_vlan_port, p_vlan_port_db);
    return ret;
}

int32
_ctc_app_pon_flex_acl_map_mac_key_field(uint8 lchip, ctc_acl_mac_key_t* p_ctc_key, ctc_field_key_t* key_field, uint16* field_num)
{
    uint32 flag = 0;


    flag = p_ctc_key->flag;
    /* mac da */
    *field_num = 0;
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_MAC_DA))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_MAC_DA;
        key_field[*field_num].ext_data = p_ctc_key->mac_da;
        key_field[*field_num].ext_mask = p_ctc_key->mac_da_mask;
        (*field_num)++;
    }

    /* mac sa */
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_MAC_SA))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_MAC_SA;
        key_field[*field_num].ext_data = p_ctc_key->mac_sa;
        key_field[*field_num].ext_mask = p_ctc_key->mac_sa_mask;
        (*field_num)++;
    }

    /* cvlan */
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_CVLAN))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_CVLAN_ID;
        key_field[*field_num].data = p_ctc_key->cvlan;
        key_field[*field_num].mask = p_ctc_key->cvlan_mask;
        (*field_num)++;
    }

    /* ctag cos */
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_CTAG_COS))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_CTAG_COS;
        key_field[*field_num].data = p_ctc_key->ctag_cos;
        key_field[*field_num].mask = p_ctc_key->ctag_cos_mask;
        (*field_num)++;
    }

    /* svlan */
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_SVLAN))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_SVLAN_ID;
        key_field[*field_num].data = p_ctc_key->svlan;
        key_field[*field_num].mask = p_ctc_key->svlan_mask;
        (*field_num)++;
    }

    /* stag cos */
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_STAG_COS))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_STAG_COS;
        key_field[*field_num].data = p_ctc_key->stag_cos;
        key_field[*field_num].mask = p_ctc_key->stag_cos_mask;
        (*field_num)++;
    }

    /* eth type */
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_ETH_TYPE))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_ETHER_TYPE;
        key_field[*field_num].data = p_ctc_key->eth_type;
        key_field[*field_num].mask = p_ctc_key->eth_type_mask;
        (*field_num)++;
    }
#if 0
    /* l2 type */
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_L2_TYPE))
    {
        key_field.type = CTC_FIELD_KEY_L2_TYPE;
        key_field.data = p_ctc_key->l2_type;
        key_field.mask = p_ctc_key->l2_type_mask;
        (*field_num)++;
    }
#endif

    /* ctag cfi */
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_CTAG_CFI))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_CTAG_CFI;
        key_field[*field_num].data = p_ctc_key->ctag_cfi;
        key_field[*field_num].mask = 1;
        (*field_num)++;
    }

    /* stag cfi */
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_STAG_CFI))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_STAG_CFI;
        key_field[*field_num].data = p_ctc_key->stag_cfi;
        key_field[*field_num].mask = 1;
        (*field_num)++;
    }

    /*stag valid*/
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_STAG_VALID))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_STAG_VALID;
        key_field[*field_num].data = p_ctc_key->stag_valid;
        key_field[*field_num].mask = 1;
        (*field_num)++;
    }

    /*ctag valid*/
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_CTAG_VALID))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_CTAG_VALID;
        key_field[*field_num].data = p_ctc_key->ctag_valid;
        key_field[*field_num].mask = 1;
        (*field_num)++;
    }

    /* vlan num */
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_VLAN_NUM))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_VLAN_NUM;
        key_field[*field_num].data = p_ctc_key->vlan_num;
        key_field[*field_num].mask = p_ctc_key->vlan_num_mask;
        (*field_num)++;
    }
#if 0
    /* metadata */
    if (CTC_FLAG_ISSET(flag, CTC_ACL_MAC_KEY_FLAG_METADATA))
    {
        key_field.type = CTC_FIELD_KEY_METADATA;
        key_field.data = p_ctc_key->metadata;
        key_field.mask = p_ctc_key->metadata_mask;
        (*field_num)++;
    }
#endif
    return CTC_E_NONE;
}

int32
_ctc_app_pon_flex_acl_map_ipv4_key_field(uint8 lchip, ctc_acl_ipv4_key_t* p_ctc_key, ctc_field_key_t* key_field, uint16* field_num)
{
    uint32 flag = 0;
    uint32 sub_flag = 0;

    /* flag */
    flag = p_ctc_key->flag;
    sub_flag = p_ctc_key->sub_flag;
    *field_num = 0;
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_MAC_DA))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_MAC_DA;
        key_field[*field_num].ext_data = p_ctc_key->mac_da;
        key_field[*field_num].ext_mask = p_ctc_key->mac_da_mask;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_MAC_SA))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_MAC_SA;
        key_field[*field_num].ext_data = p_ctc_key->mac_sa;
        key_field[*field_num].ext_mask = p_ctc_key->mac_sa_mask;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_CVLAN))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_CVLAN_ID;
        key_field[*field_num].data = p_ctc_key->cvlan;
        key_field[*field_num].mask = p_ctc_key->cvlan_mask;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_CTAG_COS))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_CTAG_COS;
        key_field[*field_num].data = p_ctc_key->ctag_cos;
        key_field[*field_num].mask = p_ctc_key->ctag_cos_mask;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_SVLAN))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_SVLAN_ID;
        key_field[*field_num].data = p_ctc_key->svlan;
        key_field[*field_num].mask = p_ctc_key->svlan_mask;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_STAG_COS))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_STAG_COS;
        key_field[*field_num].data = p_ctc_key->stag_cos;
        key_field[*field_num].mask = p_ctc_key->stag_cos_mask;
        (*field_num)++;
    }
#if 0
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_L2_TYPE))
    {
        key_field.type = CTC_FIELD_KEY_L2_TYPE;
        key_field.data = p_ctc_key->l2_type;
        key_field.mask = p_ctc_key->l2_type_mask;
        (*field_num)++;
    }
#endif
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_ETH_TYPE))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_ETHER_TYPE;
        key_field[*field_num].data = p_ctc_key->eth_type;
        key_field[*field_num].mask = p_ctc_key->eth_type_mask;
        (*field_num)++;
    }
    else if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_L3_TYPE))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_L3_TYPE;
        key_field[*field_num].data = p_ctc_key->l3_type;
        key_field[*field_num].mask = p_ctc_key->l3_type_mask;
        (*field_num)++;
    }
    else
    {
        key_field[*field_num].type = CTC_FIELD_KEY_L3_TYPE;
        key_field[*field_num].data = CTC_PARSER_L3_TYPE_IPV4;
        key_field[*field_num].mask = 0xF;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_IP_SA))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_IP_SA;
        key_field[*field_num].data = p_ctc_key->ip_sa;
        key_field[*field_num].mask = p_ctc_key->ip_sa_mask;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_IP_DA))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_IP_DA;
        key_field[*field_num].data = p_ctc_key->ip_da;
        key_field[*field_num].mask = p_ctc_key->ip_da_mask;
        (*field_num)++;
    }
#if 0
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_L4_PROTOCOL))
    {
        key_field.type = CTC_FIELD_KEY_IP_PROTOCOL;
        key_field.data = p_ctc_key->l4_protocol;
        key_field.mask = p_ctc_key->l4_protocol_mask;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_DSCP))
    {
        key_field.type = CTC_FIELD_KEY_IP_DSCP;
        key_field.data = p_ctc_key->dscp;
        key_field.mask = p_ctc_key->dscp_mask;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_PRECEDENCE))
    {
        key_field.type = CTC_FIELD_KEY_IP_PRECEDENCE;
        key_field.data = p_ctc_key->dscp;
        key_field.mask = p_ctc_key->dscp_mask & 0x7;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_IP_FRAG))
    {
        key_field.type = CTC_FIELD_KEY_IP_FRAG;
        key_field.data = p_ctc_key->ip_frag;
        key_field.mask = 1;/*useless*/
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_IP_OPTION))
    {
        key_field.type = CTC_FIELD_KEY_IP_OPTIONS;
        key_field.data = p_ctc_key->ip_option;
        key_field.mask = 1;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_ROUTED_PACKET))
    {
        key_field.type = CTC_FIELD_KEY_ROUTED_PKT;
        key_field.data = p_ctc_key->routed_packet;
        key_field.mask = 1;
        (*field_num)++;
    }
#endif
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_CTAG_CFI))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_CTAG_CFI;
        key_field[*field_num].data = p_ctc_key->ctag_cfi;
        key_field[*field_num].mask = 1;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_STAG_CFI))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_STAG_CFI;
        key_field[*field_num].data = p_ctc_key->stag_cfi;
        key_field[*field_num].mask = 1;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_STAG_VALID))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_STAG_VALID;
        key_field[*field_num].data = p_ctc_key->stag_valid;
        key_field[*field_num].mask = 1;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_CTAG_VALID))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_CTAG_VALID;
        key_field[*field_num].data = p_ctc_key->ctag_valid;
        key_field[*field_num].mask = 1;
        (*field_num)++;
    }
#if 0
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_ECN))
    {
        key_field.type = CTC_FIELD_KEY_IP_ECN;
        key_field.data = p_ctc_key->ecn;
        key_field.mask = p_ctc_key->ecn_mask;
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_METADATA))
    {
        key_field.type = CTC_FIELD_KEY_METADATA;
        key_field.data = p_ctc_key->metadata;
        key_field.mask = p_ctc_key->metadata_mask;
        (*field_num)++;
    }
#endif
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_VLAN_NUM))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_VLAN_NUM;
        key_field[*field_num].data = p_ctc_key->vlan_num;
        key_field[*field_num].mask = p_ctc_key->vlan_num_mask;
        (*field_num)++;
    }
#if 0
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_PKT_LEN_RANGE))
    {
        key_field.type = CTC_FIELD_KEY_IP_PKT_LEN_RANGE;
        key_field.data = p_ctc_key->pkt_len_min;
        key_field.mask = p_ctc_key->pkt_len_max;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV4_KEY_FLAG_IP_HDR_ERROR))
    {
        key_field.type = CTC_FIELD_KEY_IP_HDR_ERROR;
        key_field.data = p_ctc_key->ip_hdr_error;
        key_field.mask = 1;
        (*field_num)++;
    }
#endif
    if (CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_L4_SRC_PORT))
    {
        if(p_ctc_key->l4_src_port_use_mask)
        {
            key_field[*field_num].type = CTC_FIELD_KEY_L4_SRC_PORT;
        }
        else
        {
            key_field[*field_num].type = CTC_FIELD_KEY_L4_SRC_PORT_RANGE;
        }
        key_field[*field_num].data = p_ctc_key->l4_src_port_0;
        key_field[*field_num].mask = p_ctc_key->l4_src_port_1;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_L4_DST_PORT))
    {
        if(p_ctc_key->l4_dst_port_use_mask)
        {
            key_field[*field_num].type = CTC_FIELD_KEY_L4_DST_PORT;
        }
        else
        {
            key_field[*field_num].type = CTC_FIELD_KEY_L4_DST_PORT_RANGE;
        }
        key_field[*field_num].data = p_ctc_key->l4_dst_port_0;
        key_field[*field_num].mask = p_ctc_key->l4_dst_port_1;
        (*field_num)++;
    }
#if 0
    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_TCP_FLAGS))
    {
        key_field.type = CTC_FIELD_KEY_TCP_FLAGS;
        key_field.data = p_ctc_key->tcp_flags;
        if(p_ctc_key->tcp_flags_match_any)
        {
            key_field.mask = ~(p_ctc_key->tcp_flags);
        }
        else
        {
            key_field.mask = 0x3F;
        }
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_ICMP_TYPE)
        || CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_ICMP_CODE))
    {
        key_field.type = CTC_FIELD_KEY_L4_TYPE;
        key_field.data = CTC_PARSER_L4_TYPE_ICMP;
        key_field.mask = 0xF;
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_ICMP_TYPE))
    {
        key_field.type = CTC_FIELD_KEY_ICMP_TYPE;
        key_field.data = p_ctc_key->icmp_type;
        key_field.mask = p_ctc_key->icmp_type_mask;
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_ICMP_CODE))
    {
        key_field.type = CTC_FIELD_KEY_ICMP_CODE;
        key_field.data = p_ctc_key->icmp_code;
        key_field.mask = p_ctc_key->icmp_code_mask;
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_IGMP_TYPE))
    {
        key_field.type = CTC_FIELD_KEY_L4_TYPE;
        key_field.data = CTC_PARSER_L4_TYPE_IGMP;
        key_field.mask = 0xF;
        (*field_num)++;

        key_field.type = CTC_FIELD_KEY_IGMP_TYPE;
        key_field.data = p_ctc_key->igmp_type;
        key_field.mask = p_ctc_key->igmp_type_mask;
        (*field_num)++;
    }


    if (CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_ARP_OP_CODE))
    {
        key_field.type = CTC_FIELD_KEY_ARP_OP_CODE;
        key_field.data = p_ctc_key->arp_op_code;
        key_field.mask = p_ctc_key->arp_op_code_mask;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_ARP_SENDER_IP))
    {
        key_field.type = CTC_FIELD_KEY_ARP_SENDER_IP;
        key_field.data = p_ctc_key->sender_ip;
        key_field.mask = p_ctc_key->sender_ip_mask;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_ARP_TARGET_IP))
    {
        key_field.type = CTC_FIELD_KEY_ARP_TARGET_IP;
        key_field.data = p_ctc_key->target_ip;
        key_field.mask = p_ctc_key->target_ip_mask;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_ARP_PROTOCOL_TYPE))
    {
        key_field.type = CTC_FIELD_KEY_ARP_PROTOCOL_TYPE;
        key_field.data = p_ctc_key->arp_protocol_type;
        key_field.mask = p_ctc_key->arp_protocol_type_mask;
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_GRE_KEY))
    {
        key_field.type = CTC_FIELD_KEY_L4_TYPE;
        key_field.data = CTC_PARSER_L4_TYPE_GRE;
        key_field.mask = 0xF;
        (*field_num)++;

        key_field.type = CTC_FIELD_KEY_GRE_KEY;
        key_field.data = p_ctc_key->gre_key;
        key_field.mask = p_ctc_key->gre_key_mask;
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_VNI))
    {
        key_field.type = CTC_FIELD_KEY_L4_TYPE;
        key_field.data = CTC_PARSER_L4_TYPE_UDP;
        key_field.mask = 0xF;
        (*field_num)++;

        key_field.type = CTC_FIELD_KEY_L4_USER_TYPE;
        key_field.data = CTC_PARSER_L4_USER_TYPE_UDP_VXLAN;
        key_field.mask = 0xF;
        (*field_num)++;

        key_field.type = CTC_FIELD_KEY_VN_ID;
        key_field.data = p_ctc_key->vni;
        key_field.mask = p_ctc_key->vni_mask;
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_NVGRE_KEY))
    {
        key_field.type = CTC_FIELD_KEY_L4_TYPE;
        key_field.data = CTC_PARSER_L4_TYPE_GRE;
        key_field.mask = 0xF;
        (*field_num)++;

        key_field.type = CTC_FIELD_KEY_GRE_KEY;
        key_field.data = p_ctc_key->gre_key;
        key_field.mask = p_ctc_key->gre_key_mask;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(sub1_flag, CTC_ACL_IPV4_KEY_SUB1_FLAG_MPLS_LABEL_NUM))
    {
        key_field.type = CTC_FIELD_KEY_LABEL_NUM;
        key_field.data = p_ctc_key->mpls_label_num;
        key_field.mask = p_ctc_key->mpls_label_num_mask;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(sub1_flag, CTC_ACL_IPV4_KEY_SUB1_FLAG_MPLS_LABEL0))
    {
        key_field.type = CTC_FIELD_KEY_MPLS_LABEL0;
        key_field.data = (p_ctc_key->mpls_label0 >> 12) & 0xFFFFF;
        key_field.mask = (p_ctc_key->mpls_label0_mask >> 12) & 0xFFFFF;
        if(key_field.mask != 0)
        {
            (*field_num)++;
        }
        key_field.type = CTC_FIELD_KEY_MPLS_EXP0;
        key_field.data = (p_ctc_key->mpls_label0 >> 9) & 0x7;
        key_field.mask = (p_ctc_key->mpls_label0_mask >> 9) & 0x7;
        if(key_field.mask != 0)
        {
            (*field_num)++;
        }
        key_field.type = CTC_FIELD_KEY_MPLS_SBIT0;
        key_field.data = (p_ctc_key->mpls_label0 >> 8) & 0x1;
        key_field.mask = (p_ctc_key->mpls_label0_mask >> 8) & 0x1;
        if(key_field.mask != 0)
        {
            (*field_num)++;
        }
        key_field.type = CTC_FIELD_KEY_MPLS_TTL0;
        key_field.data = p_ctc_key->mpls_label0 & 0xFF;
        key_field.mask = p_ctc_key->mpls_label0_mask & 0xFF;
        if(key_field.mask != 0)
        {
            (*field_num)++;
        }
    }

    if (CTC_FLAG_ISSET(sub1_flag, CTC_ACL_IPV4_KEY_SUB1_FLAG_MPLS_LABEL1))
    {
        key_field.type = CTC_FIELD_KEY_MPLS_LABEL1;
        key_field.data = (p_ctc_key->mpls_label1 >> 12) & 0xFFFFF;
        key_field.mask = (p_ctc_key->mpls_label1_mask >> 12) & 0xFFFFF;
        (*field_num)++;
        key_field.type = CTC_FIELD_KEY_MPLS_EXP1;
        key_field.data = (p_ctc_key->mpls_label1 >> 9) & 0x7;
        key_field.mask = (p_ctc_key->mpls_label1_mask >> 9) & 0x7;
        (*field_num)++;
        key_field.type = CTC_FIELD_KEY_MPLS_SBIT1;
        key_field.data = (p_ctc_key->mpls_label1 >> 8) & 0x1;
        key_field.mask = (p_ctc_key->mpls_label1_mask >> 8) & 0x1;
        (*field_num)++;
        key_field.type = CTC_FIELD_KEY_MPLS_TTL1;
        key_field.data = p_ctc_key->mpls_label1 & 0xFF;
        key_field.mask = p_ctc_key->mpls_label1_mask & 0xFF;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(sub1_flag, CTC_ACL_IPV4_KEY_SUB1_FLAG_MPLS_LABEL2))
    {
        key_field.type = CTC_FIELD_KEY_MPLS_LABEL2;
        key_field.data = (p_ctc_key->mpls_label2 >> 12) & 0xFFFFF;
        key_field.mask = (p_ctc_key->mpls_label2_mask >> 12) & 0xFFFFF;
        (*field_num)++;
        key_field.type = CTC_FIELD_KEY_MPLS_EXP2;
        key_field.data = (p_ctc_key->mpls_label2 >> 9) & 0x7;
        key_field.mask = (p_ctc_key->mpls_label2_mask >> 9) & 0x7;
        (*field_num)++;
        key_field.type = CTC_FIELD_KEY_MPLS_SBIT2;
        key_field.data = (p_ctc_key->mpls_label2 >> 8) & 0x1;
        key_field.mask = (p_ctc_key->mpls_label2_mask >> 8) & 0x1;
        (*field_num)++;
        key_field.type = CTC_FIELD_KEY_MPLS_TTL2;
        key_field.data = p_ctc_key->mpls_label2 & 0xFF;
        key_field.mask = p_ctc_key->mpls_label2_mask & 0xFF;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(sub3_flag, CTC_ACL_IPV4_KEY_SUB3_FLAG_ETHOAM_LEVEL))
    {
        key_field.type = CTC_FIELD_KEY_ETHER_OAM_LEVEL;
        key_field.data = p_ctc_key->ethoam_level;
        key_field.mask = p_ctc_key->ethoam_level_mask;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(sub3_flag, CTC_ACL_IPV4_KEY_SUB3_FLAG_ETHOAM_OPCODE))
    {
        key_field.type = CTC_FIELD_KEY_ETHER_OAM_OP_CODE;
        key_field.data = p_ctc_key->ethoam_op_code;
        key_field.mask = p_ctc_key->ethoam_op_code_mask;
        (*field_num)++;
    }
#endif
    return CTC_E_NONE;
}

int32
_ctc_app_pon_flex_acl_map_ipv6_key_field(uint8 lchip, ctc_acl_ipv6_key_t* p_ctc_key, ctc_field_key_t* key_field, uint16* field_num)
{
    uint32 flag = 0;
    uint32 sub_flag = 0;


    flag = p_ctc_key->flag;
    sub_flag = p_ctc_key->sub_flag;
    key_field[*field_num].type = CTC_FIELD_KEY_L3_TYPE;
    key_field[*field_num].data = CTC_PARSER_L3_TYPE_IPV6;
    key_field[*field_num].mask = 0xF;
    *field_num = 1;

    if(CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_MAC_DA))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_MAC_DA;
        key_field[*field_num].ext_data = p_ctc_key->mac_da;
        key_field[*field_num].ext_mask = p_ctc_key->mac_da_mask;
        (*field_num)++;
    }
    if(CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_MAC_SA))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_MAC_SA;
        key_field[*field_num].ext_data = p_ctc_key->mac_sa;
        key_field[*field_num].ext_mask = p_ctc_key->mac_sa_mask;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_CVLAN))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_CVLAN_ID;
        key_field[*field_num].data = p_ctc_key->cvlan;
        key_field[*field_num].mask = p_ctc_key->cvlan_mask;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_CTAG_COS))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_CTAG_COS;
        key_field[*field_num].data = p_ctc_key->ctag_cos;
        key_field[*field_num].mask = p_ctc_key->ctag_cos_mask;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_SVLAN))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_SVLAN_ID;
        key_field[*field_num].data = p_ctc_key->svlan;
        key_field[*field_num].mask = p_ctc_key->svlan_mask;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_STAG_COS))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_STAG_COS;
        key_field[*field_num].data = p_ctc_key->stag_cos;
        key_field[*field_num].mask = p_ctc_key->stag_cos_mask;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_ETH_TYPE))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_ETHER_TYPE;
        key_field[*field_num].data = p_ctc_key->eth_type;
        key_field[*field_num].mask = p_ctc_key->eth_type_mask;
        (*field_num)++;
    }
#if 0
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_L2_TYPE))
    {
        key_field.type = CTC_FIELD_KEY_L2_TYPE;
        key_field.data = p_ctc_key->l2_type;
        key_field.mask = p_ctc_key->l2_type_mask;
        (*field_num)++;
    }
#endif
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_L3_TYPE))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_L3_TYPE;
        key_field[*field_num].data = p_ctc_key->l3_type;
        key_field[*field_num].mask = p_ctc_key->l3_type_mask;
        (*field_num)++;
    }
    else
    {
        key_field[*field_num].type = CTC_FIELD_KEY_L3_TYPE;
        key_field[*field_num].data = CTC_PARSER_L3_TYPE_IPV6;
        key_field[*field_num].mask = 0xF;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_IP_SA))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_IPV6_SA;
        key_field[*field_num].ext_data = p_ctc_key->ip_sa;
        key_field[*field_num].ext_mask = p_ctc_key->ip_sa_mask;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_IP_DA))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_IPV6_DA;
        key_field[*field_num].ext_data = p_ctc_key->ip_da;
        key_field[*field_num].ext_mask = p_ctc_key->ip_da_mask;
        (*field_num)++;
    }
#if 0
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_L4_PROTOCOL))
    {
        key_field.type = CTC_FIELD_KEY_IP_PROTOCOL;
        key_field.data = p_ctc_key->l4_protocol;
        key_field.mask = p_ctc_key->l4_protocol_mask;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_DSCP))
    {
        key_field.type = CTC_FIELD_KEY_IP_DSCP;
        key_field.data = p_ctc_key->dscp;
        key_field.mask = p_ctc_key->dscp_mask;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_PRECEDENCE))
    {
        key_field.type = CTC_FIELD_KEY_IP_PRECEDENCE;
        key_field.data = p_ctc_key->dscp;
        key_field.mask = p_ctc_key->dscp_mask & 0x7;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_IP_FRAG))
    {
        key_field.type = CTC_FIELD_KEY_IP_FRAG;
        key_field.data = p_ctc_key->ip_frag;
        key_field.mask = 1;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_IP_OPTION))
    {
        key_field.type = CTC_FIELD_KEY_IP_OPTIONS;
        key_field.data = p_ctc_key->ip_option;
        key_field.mask = 1;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_ROUTED_PACKET))
    {
        key_field.type = CTC_FIELD_KEY_ROUTED_PKT;
        key_field.data = p_ctc_key->routed_packet;
        key_field.mask = 1;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_FLOW_LABEL))
    {
        key_field.type = CTC_FIELD_KEY_IPV6_FLOW_LABEL;
        key_field.data = p_ctc_key->flow_label;
        key_field.mask = p_ctc_key->flow_label_mask;
        (*field_num)++;
    }
#endif
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_CTAG_CFI))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_CTAG_CFI;
        key_field[*field_num].data = p_ctc_key->ctag_cfi;
        key_field[*field_num].mask = 1;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_STAG_CFI))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_STAG_CFI;
        key_field[*field_num].data = p_ctc_key->stag_cfi;
        key_field[*field_num].mask = 1;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_STAG_VALID))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_STAG_VALID;
        key_field[*field_num].data = p_ctc_key->stag_valid;
        key_field[*field_num].mask = 1;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_CTAG_VALID))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_CTAG_VALID;
        key_field[*field_num].data = p_ctc_key->ctag_valid;
        key_field[*field_num].mask = 1;
        (*field_num)++;
    }
#if 0
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_ECN))
    {
        key_field.type = CTC_FIELD_KEY_IP_ECN;
        key_field.data = p_ctc_key->ecn;
        key_field.mask = p_ctc_key->ecn_mask;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_METADATA))
    {
        key_field.type = CTC_FIELD_KEY_METADATA;
        key_field.data = p_ctc_key->metadata;
        key_field.mask = p_ctc_key->metadata_mask;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_UDF))
    {
        return CTC_E_NOT_SUPPORT;
    }
#endif
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_VLAN_NUM))
    {
        key_field[*field_num].type = CTC_FIELD_KEY_VLAN_NUM;
        key_field[*field_num].data = p_ctc_key->vlan_num;
        key_field[*field_num].mask = p_ctc_key->vlan_num_mask;
        (*field_num)++;
    }
#if 0
    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_PKT_LEN_RANGE))
    {
        key_field.type = CTC_FIELD_KEY_IP_PKT_LEN_RANGE;
        key_field.data = p_ctc_key->pkt_len_min;
        key_field.mask = p_ctc_key->pkt_len_max;
        (*field_num)++;
    }

    if (CTC_FLAG_ISSET(flag, CTC_ACL_IPV6_KEY_FLAG_IP_HDR_ERROR))
    {
        key_field.type = CTC_FIELD_KEY_IP_HDR_ERROR;
        key_field.data = p_ctc_key->ip_hdr_error;
        key_field.mask = 1;
        (*field_num)++;
    }
#endif
    /*The sequence is according to ctc_acl_ipv6_key_sub_flag_t */
    if (CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV6_KEY_SUB_FLAG_L4_SRC_PORT))
    {
        if(p_ctc_key->l4_src_port_use_mask)
        {
            key_field[*field_num].type = CTC_FIELD_KEY_L4_SRC_PORT;
        }
        else
        {
            key_field[*field_num].type = CTC_FIELD_KEY_L4_SRC_PORT_RANGE;
        }
        key_field[*field_num].data = p_ctc_key->l4_src_port_0;
        key_field[*field_num].mask = p_ctc_key->l4_src_port_1;
        (*field_num)++;
    }
    if (CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV6_KEY_SUB_FLAG_L4_DST_PORT))
    {
        if(p_ctc_key->l4_dst_port_use_mask)
        {
            key_field[*field_num].type = CTC_FIELD_KEY_L4_DST_PORT;
        }
        else
        {
            key_field[*field_num].type = CTC_FIELD_KEY_L4_DST_PORT_RANGE;
        }
        key_field[*field_num].data = p_ctc_key->l4_dst_port_0;
        key_field[*field_num].mask = p_ctc_key->l4_dst_port_1;
        (*field_num)++;
    }
#if 0
    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV6_KEY_SUB_FLAG_TCP_FLAGS))
    {
        key_field.type = CTC_FIELD_KEY_TCP_FLAGS;
        key_field.data = p_ctc_key->tcp_flags;
        if(p_ctc_key->tcp_flags_match_any)
        {
            key_field.mask = ~(p_ctc_key->tcp_flags);
        }
        else
        {
            key_field.mask = 0x3F;
        }
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_ICMP_TYPE)
        || CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV4_KEY_SUB_FLAG_ICMP_CODE))
    {
        key_field.type = CTC_FIELD_KEY_L4_TYPE;
        key_field.data = CTC_PARSER_L4_TYPE_ICMP;
        key_field.mask = 0xF;
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV6_KEY_SUB_FLAG_ICMP_TYPE))
    {
        key_field.type = CTC_FIELD_KEY_ICMP_TYPE;
        key_field.data = p_ctc_key->icmp_type;
        key_field.mask = p_ctc_key->icmp_type_mask;
        (*field_num)++;
    }
    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV6_KEY_SUB_FLAG_ICMP_CODE))
    {
        key_field.type = CTC_FIELD_KEY_ICMP_CODE;
        key_field.data = p_ctc_key->icmp_code;
        key_field.mask = p_ctc_key->icmp_code_mask;
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV6_KEY_SUB_FLAG_GRE_KEY)
        || CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV6_KEY_SUB_FLAG_NVGRE_KEY))
    {
    key_field.type = CTC_FIELD_KEY_L4_TYPE;
        key_field.data = CTC_PARSER_L4_TYPE_GRE;
        key_field.mask = 0xF;
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV6_KEY_SUB_FLAG_GRE_KEY))
    {
        key_field.type = CTC_FIELD_KEY_GRE_KEY;
        key_field.data = p_ctc_key->gre_key;
        key_field.mask = p_ctc_key->gre_key_mask;
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV6_KEY_SUB_FLAG_NVGRE_KEY))
    {
        key_field.type = CTC_FIELD_KEY_GRE_KEY;
        key_field.data = p_ctc_key->gre_key;
        key_field.mask = p_ctc_key->gre_key_mask;
        (*field_num)++;
    }

    if(CTC_FLAG_ISSET(sub_flag, CTC_ACL_IPV6_KEY_SUB_FLAG_VNI))
    {
        key_field.type = CTC_FIELD_KEY_L4_TYPE;
        key_field.data = CTC_PARSER_L4_TYPE_UDP;
        key_field.mask = 0xF;
        (*field_num)++;

        key_field.type = CTC_FIELD_KEY_L4_USER_TYPE;
        key_field.data = CTC_PARSER_L4_USER_TYPE_UDP_VXLAN;
        key_field.mask = 0xF;
        (*field_num)++;

        key_field.type = CTC_FIELD_KEY_VN_ID;
        key_field.data = p_ctc_key->vni;
        key_field.mask = p_ctc_key->vni_mask;
        (*field_num)++;
    }
#endif
    return CTC_E_NONE;

}

STATIC int32
_ctc_app_pon_check_policer_id(uint8 lchip, uint16 policer_id, uint8 dir)
{
    int32   ret = CTC_E_NONE;
    ctc_qos_policer_t qos_policer ;

    sal_memset(&qos_policer, 0, sizeof(qos_policer));

    qos_policer.id.policer_id = policer_id;
    qos_policer.dir = CTC_INGRESS;
    qos_policer.type = CTC_QOS_POLICER_TYPE_FLOW;

    if (policer_id)
    {
        ret = ctc_qos_get_policer(&qos_policer);
        if (!qos_policer.hbwp_en && (CTC_EGRESS == dir))      /*egress only support hbwp policer*/
        {
            CTC_APP_DBG_ERROR("Only Policer level 0 and hbwp is support in downstream !\n");
            return CTC_E_NOT_SUPPORT;
        }
    }

    return ret;
}

STATIC int32
_ctc_app_pon_vlan_mapping(uint8 lchip, ctc_app_pon_service_t* p_vlan_port,
                               ctc_vlan_mapping_t* p_vlan_mapping, ctc_scl_vlan_edit_t* p_vlan_edit)
{
    CTC_APP_PON_INIT_CHECK();

    /*SVLAN op*/
    switch(p_vlan_port->ingress_vlan_action_set.svid)
    {
        case CTC_APP_PON_VLAN_ACTION_ADD:
            CTC_VLAN_RANGE_CHECK(p_vlan_port->ingress_vlan_action_set.new_svid);
            if (p_vlan_mapping)
            {
                CTC_SET_FLAG(p_vlan_mapping->action, CTC_VLAN_MAPPING_OUTPUT_SVID);
                p_vlan_mapping->stag_op = CTC_VLAN_TAG_OP_ADD;
                p_vlan_mapping->svid_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_mapping->new_svid = p_vlan_port->ingress_vlan_action_set.new_svid;
            }
            else
            {
                p_vlan_edit->stag_op = CTC_VLAN_TAG_OP_ADD;
                p_vlan_edit->svid_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_edit->svid_new = p_vlan_port->ingress_vlan_action_set.new_svid;
            }
            break;

        case CTC_APP_PON_VLAN_ACTION_REPLACE:
            CTC_VLAN_RANGE_CHECK(p_vlan_port->ingress_vlan_action_set.new_svid);
            if (p_vlan_mapping)
            {
                CTC_SET_FLAG(p_vlan_mapping->action, CTC_VLAN_MAPPING_OUTPUT_SVID);
                p_vlan_mapping->stag_op = CTC_VLAN_TAG_OP_REP;
                p_vlan_mapping->svid_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_mapping->new_svid = p_vlan_port->ingress_vlan_action_set.new_svid;
            }
            else
            {
                p_vlan_edit->stag_op = CTC_VLAN_TAG_OP_REP;
                p_vlan_edit->svid_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_edit->svid_new = p_vlan_port->ingress_vlan_action_set.new_svid;
            }
            break;

        case CTC_APP_PON_VLAN_ACTION_DEL:
            if (p_vlan_mapping)
            {
                CTC_SET_FLAG(p_vlan_mapping->action, CTC_VLAN_MAPPING_OUTPUT_SVID);
                p_vlan_mapping->stag_op = CTC_VLAN_TAG_OP_DEL;
            }
            else
            {
                p_vlan_edit->stag_op = CTC_VLAN_TAG_OP_DEL;
            }
            return CTC_E_INVALID_PARAM;
            break;

         case CTC_APP_PON_VLAN_ACTION_NONE:
            if (p_vlan_mapping)
            {
                CTC_SET_FLAG(p_vlan_mapping->action, CTC_VLAN_MAPPING_OUTPUT_SVID);
                p_vlan_mapping->stag_op = CTC_VLAN_TAG_OP_VALID;
            }
            else
            {
                p_vlan_edit->stag_op = CTC_VLAN_TAG_OP_NONE;
            }
            break;

        default:
            return CTC_E_INVALID_PARAM;
    }

    switch(p_vlan_port->ingress_vlan_action_set.cvid)
    {
        case CTC_APP_PON_VLAN_ACTION_ADD:
            CTC_VLAN_RANGE_CHECK(p_vlan_port->ingress_vlan_action_set.new_cvid);
            if (p_vlan_mapping)
            {
                CTC_SET_FLAG(p_vlan_mapping->action, CTC_VLAN_MAPPING_OUTPUT_CVID);
                p_vlan_mapping->ctag_op = CTC_VLAN_TAG_OP_ADD;
                p_vlan_mapping->cvid_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_mapping->new_cvid = p_vlan_port->ingress_vlan_action_set.new_cvid;
            }
            else
            {
                p_vlan_edit->ctag_op = CTC_VLAN_TAG_OP_ADD;
                p_vlan_edit->cvid_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_edit->cvid_new = p_vlan_port->ingress_vlan_action_set.new_cvid;
            }
            break;

        case CTC_APP_PON_VLAN_ACTION_REPLACE:
            CTC_VLAN_RANGE_CHECK(p_vlan_port->ingress_vlan_action_set.new_cvid);
            if (p_vlan_mapping)
            {
                CTC_SET_FLAG(p_vlan_mapping->action, CTC_VLAN_MAPPING_OUTPUT_CVID);
                p_vlan_mapping->ctag_op = CTC_VLAN_TAG_OP_REP;
                p_vlan_mapping->cvid_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_mapping->new_cvid = p_vlan_port->ingress_vlan_action_set.new_cvid;
            }
            else
            {
                p_vlan_edit->ctag_op = CTC_VLAN_TAG_OP_REP;
                p_vlan_edit->cvid_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_edit->cvid_new = p_vlan_port->ingress_vlan_action_set.new_cvid;
            }
            break;

        case CTC_APP_PON_VLAN_ACTION_DEL:
            if (p_vlan_mapping)
            {
                CTC_SET_FLAG(p_vlan_mapping->action, CTC_VLAN_MAPPING_OUTPUT_CVID);
                p_vlan_mapping->ctag_op = CTC_VLAN_TAG_OP_DEL;
            }
            else
            {
                p_vlan_edit->ctag_op = CTC_VLAN_TAG_OP_DEL;
            }
            return CTC_E_INVALID_PARAM;
            break;


         case CTC_APP_PON_VLAN_ACTION_NONE:
            if (p_vlan_mapping)
            {
                CTC_SET_FLAG(p_vlan_mapping->action, CTC_VLAN_MAPPING_OUTPUT_CVID);
                p_vlan_mapping->ctag_op = CTC_VLAN_TAG_OP_VALID;
            }
            else
            {
                p_vlan_edit->ctag_op = CTC_VLAN_TAG_OP_NONE;
            }
            break;

        default:
            return CTC_E_INVALID_PARAM;
    }

    switch(p_vlan_port->ingress_vlan_action_set.scos)
    {
        case CTC_APP_PON_VLAN_ACTION_ADD:
            if (p_vlan_mapping)
            {
                p_vlan_mapping->scos_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_mapping->new_scos = p_vlan_port->ingress_vlan_action_set.new_scos;
                CTC_SET_FLAG(p_vlan_mapping->action, CTC_VLAN_MAPPING_OUTPUT_SCOS);
            }
            else
            {
                p_vlan_edit->scos_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_edit->scos_new = p_vlan_port->ingress_vlan_action_set.new_scos;
            }
            break;

        case CTC_APP_PON_VLAN_ACTION_REPLACE:
            if (p_vlan_mapping)
            {
                p_vlan_mapping->scos_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_mapping->new_scos = p_vlan_port->ingress_vlan_action_set.new_scos;
                CTC_SET_FLAG(p_vlan_mapping->action, CTC_VLAN_MAPPING_OUTPUT_SCOS);
                if(CTC_VLAN_TAG_OP_NONE == p_vlan_mapping->stag_op)
                {
                    p_vlan_mapping->stag_op = CTC_VLAN_TAG_OP_REP;
                }
            }
            else
            {
                p_vlan_edit->scos_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_edit->scos_new = p_vlan_port->ingress_vlan_action_set.new_scos;
                if(CTC_VLAN_TAG_OP_NONE == p_vlan_edit->stag_op)
                {
                    p_vlan_edit->stag_op = CTC_VLAN_TAG_OP_REP;
                }
            }
            break;

        case  CTC_APP_PON_VLAN_ACTION_NONE:
            if (p_vlan_mapping)
            {
                p_vlan_mapping->scos_sl = CTC_VLAN_TAG_SL_AS_PARSE;
            }
            else
            {
                p_vlan_edit->scos_sl = CTC_VLAN_TAG_SL_AS_PARSE;
            }
            break;

        default:
            return CTC_E_INVALID_PARAM;
    }

    switch(p_vlan_port->ingress_vlan_action_set.ccos)
    {
        case CTC_APP_PON_VLAN_ACTION_ADD:
            if (p_vlan_mapping)
            {
                p_vlan_mapping->ccos_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_mapping->new_ccos = p_vlan_port->ingress_vlan_action_set.new_ccos;
                CTC_SET_FLAG(p_vlan_mapping->action, CTC_VLAN_MAPPING_OUTPUT_CCOS);
            }
            else
            {
                p_vlan_edit->ccos_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_edit->ccos_new = p_vlan_port->ingress_vlan_action_set.new_ccos;
            }
            break;

        case CTC_APP_PON_VLAN_ACTION_REPLACE:
            if (p_vlan_mapping)
            {
                p_vlan_mapping->ccos_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_mapping->new_ccos = p_vlan_port->ingress_vlan_action_set.new_ccos;
                CTC_SET_FLAG(p_vlan_mapping->action, CTC_VLAN_MAPPING_OUTPUT_CCOS);
                if(CTC_VLAN_TAG_OP_NONE == p_vlan_mapping->ctag_op)
                {
                    p_vlan_mapping->ctag_op = CTC_VLAN_TAG_OP_REP;
                }
            }
            else
            {
                p_vlan_edit->ccos_sl = CTC_VLAN_TAG_SL_NEW;
                p_vlan_edit->ccos_new = p_vlan_port->ingress_vlan_action_set.new_ccos;
                if(CTC_VLAN_TAG_OP_NONE == p_vlan_edit->ctag_op)
                {
                    p_vlan_edit->ctag_op = CTC_VLAN_TAG_OP_REP;
                }
            }
            break;

         case CTC_APP_PON_VLAN_ACTION_NONE:
            if (p_vlan_mapping)
            {
                p_vlan_mapping->ccos_sl = CTC_VLAN_TAG_SL_AS_PARSE;
            }
            else
            {
                p_vlan_edit->ccos_sl = CTC_VLAN_TAG_SL_AS_PARSE;
            }
            break;

        default:
            return CTC_E_INVALID_PARAM;
    }

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_scl_xlate_mapping(uint8 lchip, ctc_app_pon_service_t* p_vlan_port,
                               ctc_scl_vlan_edit_t* p_xlate)
{
    CTC_APP_PON_INIT_CHECK();

    /* SVLAN op */
    switch(p_vlan_port->egress_vlan_action_set.svid)
    {
        case CTC_APP_VLAN_ACTION_DEL:
            p_xlate->stag_op = CTC_VLAN_TAG_OP_DEL;
            break;

        case CTC_APP_VLAN_ACTION_REPLACE:
            p_xlate->stag_op = CTC_VLAN_TAG_OP_REP;
            p_xlate->svid_sl = CTC_VLAN_TAG_SL_NEW;
            p_xlate->svid_new = p_vlan_port->egress_vlan_action_set.new_svid;
            break;

        case CTC_APP_VLAN_ACTION_NONE:
            break;

        case CTC_APP_VLAN_ACTION_ADD:
        default:
            return CTC_E_INVALID_PARAM;
    }

    /* CVLAN op */
    switch(p_vlan_port->egress_vlan_action_set.cvid)
    {
        case CTC_APP_VLAN_ACTION_DEL:
            p_xlate->ctag_op = CTC_VLAN_TAG_OP_DEL;
            break;

        case CTC_APP_VLAN_ACTION_REPLACE:
            p_xlate->ctag_op = CTC_VLAN_TAG_OP_REP;
            p_xlate->cvid_sl = CTC_VLAN_TAG_SL_NEW;
            p_xlate->cvid_new = p_vlan_port->egress_vlan_action_set.new_cvid;
            break;

        case CTC_APP_VLAN_ACTION_NONE:
            break;

        case CTC_APP_VLAN_ACTION_ADD:
        default:
            return CTC_E_INVALID_PARAM;
    }


    /* SCOS op */
    switch(p_vlan_port->egress_vlan_action_set.scos)
    {
        case CTC_APP_VLAN_ACTION_NONE:
            break;

        case CTC_APP_VLAN_ACTION_ADD:
        case CTC_APP_VLAN_ACTION_REPLACE:
            p_xlate->stag_op = CTC_VLAN_TAG_OP_REP;
            p_xlate->scos_sl = CTC_VLAN_TAG_SL_NEW;
            p_xlate->scos_new = p_vlan_port->egress_vlan_action_set.new_scos;

         break;
        case CTC_APP_VLAN_ACTION_DEL:
            break;
        default:
            return CTC_E_INVALID_PARAM;
    }

    /* CCOS op */
    switch(p_vlan_port->egress_vlan_action_set.ccos)
    {
        case CTC_APP_VLAN_ACTION_NONE:
            break;

        case CTC_APP_VLAN_ACTION_ADD:
        case CTC_APP_VLAN_ACTION_REPLACE:
            return CTC_E_INVALID_PARAM;

        case CTC_APP_VLAN_ACTION_DEL:
            break;

        default:
            return CTC_E_INVALID_PARAM;
    }

    return CTC_E_NONE;
}

int32
_ctc_app_pon_flex_key_mapping(uint8 lchip, ctc_app_pon_service_t* p_vlan_port, ctc_field_key_t* key_field, ctc_pon_vlan_port_t* vlan_port)
{
    switch(p_vlan_port->flex_key.type)
    {
       case CTC_ACL_KEY_MAC:
           vlan_port->criteria = APP_FROM_TMM?CTC_PON_VLAN_PORT_MATCH_FLEX_IPV4:CTC_PON_VLAN_PORT_MATCH_FLEX_MAC;
           _ctc_app_pon_flex_acl_map_mac_key_field(lchip, &p_vlan_port->flex_key.u.mac_key, key_field, &vlan_port->fields_num);
           break;
       case CTC_ACL_KEY_IPV4:
           vlan_port->criteria = CTC_PON_VLAN_PORT_MATCH_FLEX_IPV4;
           _ctc_app_pon_flex_acl_map_ipv4_key_field(lchip, &p_vlan_port->flex_key.u.ipv4_key , key_field, &vlan_port->fields_num);
           break;
       case CTC_ACL_KEY_IPV6:
           vlan_port->criteria = CTC_PON_VLAN_PORT_MATCH_FLEX_IPV6;
           _ctc_app_pon_flex_acl_map_ipv6_key_field(lchip, &p_vlan_port->flex_key.u.ipv6_key , key_field, &vlan_port->fields_num);
           break;
       default:
           return CTC_E_NOT_SUPPORT;
    }
    return CTC_E_NONE;
}

int32
_ctc_app_pon_match_key_mapping(uint8 lchip, ctc_app_pon_service_t* p_vlan_port, ctc_field_key_t* key_field, ctc_pon_vlan_port_t* vlan_port)
{
    uint16* field_num = &vlan_port->fields_num;

    *field_num = 0;
    if(p_vlan_port->match_svlan_end)
    {
        key_field[*field_num].type = CTC_FIELD_KEY_SVLAN_RANGE;
        key_field[*field_num].data = p_vlan_port->match_svlan;
        key_field[*field_num].mask = p_vlan_port->match_svlan_end;
    }
    else
    {
        key_field[*field_num].data = p_vlan_port->match_svlan;
        key_field[*field_num].type = CTC_FIELD_KEY_SVLAN_ID;

    }

    (*field_num)++;

    if(p_vlan_port->match_cvlan_end)
    {
        key_field[*field_num].data = p_vlan_port->match_cvlan;
        key_field[*field_num].mask = p_vlan_port->match_cvlan_end;
        key_field[*field_num].type = CTC_FIELD_KEY_CVLAN_RANGE;
    }
    else
    {
        key_field[*field_num].data = p_vlan_port->match_cvlan;
        key_field[*field_num].type = CTC_FIELD_KEY_CVLAN_ID;
    }

    (*field_num)++;
    return CTC_E_NONE;
}

int32
_ctc_app_pon_create_downlink_service(uint8 lchip, ctc_app_pon_service_t* p_vlan_port, ctc_app_pon_fid_db_t* p_port_fid_db)
{
    ctc_field_key_t match_fields[2] ;
    ctc_pon_vlan_port_t vlan_port;
    uint8 vdev_max;
    uint8 vlan_glb_vdev_en = 0 ;
    uint8 vdev_id;
    uint8 index;

    sal_memset(&match_fields, 0, sizeof(ctc_field_key_t)*2);
    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    match_fields[0].data = p_port_fid_db->pkt_svlan;
    match_fields[0].type = CTC_FIELD_KEY_SVLAN_ID;
    vdev_id = p_port_fid_db->vdev_id;
    vdev_max = vdev_id + 1;
    if(CTC_IS_BIT_SET(p_app_pon_master->vlan_glb_vdev[p_port_fid_db->pkt_svlan/32], p_port_fid_db->pkt_svlan%32))
    {
        vlan_glb_vdev_en = 1;
    }
    if(vlan_glb_vdev_en)
    {
        vdev_max = p_app_pon_master->vdev_num;
        vdev_id = 0;
    }
    if(p_app_pon_master->fid_mode)
    {
        vlan_port.criteria = CTC_PON_VLAN_PORT_MATCH_SVLAN;
        vlan_port.fields_num = 1;
    }
    else
    {
        vlan_port.criteria = CTC_PON_VLAN_PORT_MATCH_SVLAN_CVLAN;
        vlan_port.fields_num = 2;
        match_fields[1].data = p_port_fid_db->pkt_cvlan;
        match_fields[1].type = CTC_FIELD_KEY_CVLAN_ID;
        if(NULL != p_vlan_port)
        {
            if(p_vlan_port->match_svlan_end)
            {
                match_fields[1].type = CTC_FIELD_KEY_CVLAN_RANGE;
                match_fields[1].data = p_vlan_port->match_svlan;
                match_fields[1].mask = p_vlan_port->match_svlan_end;
            }
        }
    }
    if(!p_port_fid_db->pkt_cvlan)
    {
        CTC_SET_FLAG(vlan_port.flag,CTC_PON_VLAN_PORT_FLAG_KNOWN_MCAST_SERVICE);
    }
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_NNI);
    vlan_port.fid = p_port_fid_db->fid;
    vlan_port.volt_tag_valid = 1;
    vlan_port.volt_tag = p_app_pon_master->vdev_base_vlan + (vlan_glb_vdev_en? p_app_pon_master->vdev_num: p_port_fid_db->vdev_id);
    vlan_port.match_fields = &match_fields[0];
    for (index = vdev_id; index<vdev_max; index++)
    {
        vlan_port.gport = p_app_pon_master->nni_port[index];
        vlan_port.logic_port = p_app_pon_master->nni_logic_port[index];
        vlan_port.vlan_port_id = p_port_fid_db->vlan_port_id + index - vdev_id;
        CTC_ERROR_RETURN(ctc_pon_create_vlan_port(&vlan_port));
    }

    return CTC_E_NONE;
}

int32
_ctc_app_pon_destroy_downlink_service(uint8 lchip, uint32 vlan_port_id, uint8 vdev_id, uint16 pkt_svlan)
{
    uint8 index = 0;
    uint8 vdev_max = 0;
    uint8 vlan_glb_vdev_en = 0;
    ctc_pon_vlan_port_t vlan_port;

    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    vdev_id = vdev_id;
    vdev_max = vdev_id + 1;
    if(CTC_IS_BIT_SET(p_app_pon_master->vlan_glb_vdev[pkt_svlan/32], pkt_svlan%32))
    {
        vlan_glb_vdev_en = 1;
    }

    if(vlan_glb_vdev_en)
    {
       vdev_max = p_app_pon_master->vdev_num;
       vdev_id = 0;
    }
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_NNI);
    for (index = vdev_id; index<vdev_max; index++)
    {
       vlan_port.gport = p_app_pon_master->nni_port[index];
       vlan_port.vlan_port_id = vlan_port_id + index - vdev_id;
       ctc_pon_destroy_vlan_port(&vlan_port);
    }

    return CTC_E_NONE;
}

int32
_ctc_app_vlan_remove_pon_service_from_default_entry(ctc_app_pon_gem_port_db_t* gem_port_db_tmp, void* vlan_port_db)
{
    ctc_app_pon_db_t* vlan_port_db_tmp = (ctc_app_pon_db_t*)vlan_port_db;
    ctc_l2dflt_addr_t l2dflt;
    ctc_mcast_nh_param_group_t mcast_group;
    uint16 mcast_group_id;
    uint32 nh_id;

    if(gem_port_db_tmp->port != vlan_port_db_tmp->port)
    {
        return 0;
    }

    sal_memset(&l2dflt, 0, sizeof(l2dflt));
    l2dflt.fid = vlan_port_db_tmp->fid;
    l2dflt.l2mc_grp_id = vlan_port_db_tmp->fid;
    l2dflt.logic_port = gem_port_db_tmp->logic_port;
    l2dflt.with_nh = 1;
    l2dflt.member.nh_id = gem_port_db_tmp->pon_downlink_nhid;

    ctc_l2_remove_port_from_default_entry(&l2dflt);
    if(p_app_pon_master->mcast_tunnel_vlan == 0xffff)
    {
        sal_memset(&l2dflt, 0, sizeof(l2dflt));
        l2dflt.fid = vlan_port_db_tmp->fid;
        ctc_l2_get_default_entry_features(&l2dflt);
        mcast_group_id = ENCODE_MCAST_GROUP_ID(l2dflt.l2mc_grp_id, 1);
        ctc_nh_get_mcast_nh(mcast_group_id, &nh_id);
        sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
        mcast_group.mc_grp_id = mcast_group_id;
        mcast_group.opcode = CTC_NH_PARAM_MCAST_DEL_MEMBER;
        mcast_group.mem_info.ref_nhid = gem_port_db_tmp->pon_downlink_nhid;
        mcast_group.mem_info.logic_dest_port = gem_port_db_tmp->logic_port;
        mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
        ctc_nh_update_mcast(nh_id, &mcast_group);
    }

    return CTC_E_NONE;

}


int32
_ctc_app_pon_update_service_vdev_id(uint8 lchip, ctc_app_pon_db_t* vlan_port_db_tmp, uint16 lport, uint8 vdev_id)
{
    uint8 alloc = 0;
    uint32 nni_vlan_port_id = 0;
    ctc_app_pon_db_t vlan_port_db;
    ctc_app_pon_fid_db_t port_fid_db;
    ctc_app_pon_fid_db_t* p_port_fid_db = NULL;
    ctc_app_pon_service_t* p_vlan_port = NULL;
    ctc_app_pon_db_t* p_vlan_port_db = NULL;
    ctc_pon_vlan_port_t vlan_port;
    ctc_field_key_t match_fields[2];

    sal_memset(&port_fid_db, 0, sizeof(ctc_app_pon_fid_db_t));
    port_fid_db.vdev_id = vlan_port_db_tmp->vdev_id;
    port_fid_db.pkt_svlan = vlan_port_db_tmp->pkt_svlan;
    port_fid_db.pkt_cvlan = p_app_pon_master->fid_mode?0:vlan_port_db_tmp->pkt_cvlan;
    p_port_fid_db = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
    if(NULL != p_port_fid_db)
    {
        nni_vlan_port_id = p_port_fid_db->vlan_port_id;
        p_port_fid_db = NULL;
    }
    ctc_spool_remove(p_app_pon_master->fid_spool, &port_fid_db, NULL);
    p_port_fid_db = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
    if(NULL == p_port_fid_db)
    {
        sal_memset(&vlan_port, 0, sizeof(vlan_port));
        CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_NNI);
        vlan_port.gport = p_app_pon_master->nni_port[vlan_port_db_tmp->vdev_id];
        vlan_port.vlan_port_id = nni_vlan_port_id;
        ctc_pon_destroy_vlan_port(&vlan_port);
    }
    port_fid_db.vdev_id = vdev_id;
    p_port_fid_db = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
    if(NULL == p_port_fid_db)
    {
        alloc = 1;
    }
    CTC_ERROR_RETURN(ctc_spool_add(p_app_pon_master->fid_spool, &port_fid_db, NULL, &p_port_fid_db));
    if(alloc)
    {
        sal_memset(&vlan_port, 0, sizeof(vlan_port));
        sal_memset(&match_fields, 0, sizeof(ctc_field_key_t)*2);
        match_fields[0].data = vlan_port_db_tmp->pkt_svlan;
        match_fields[0].type = CTC_FIELD_KEY_SVLAN_ID;
        CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_NNI);
        if(p_app_pon_master->fid_mode)
        {
            vlan_port.criteria = CTC_PON_VLAN_PORT_MATCH_SVLAN;
            vlan_port.fields_num = 1;
        }
        else
        {
            vlan_port.criteria = CTC_PON_VLAN_PORT_MATCH_SVLAN_CVLAN;
            vlan_port.fields_num = 2;
            if(vlan_port_db_tmp->match_svlan_end)
            {
                match_fields[1].type = CTC_FIELD_KEY_CVLAN_RANGE;
                match_fields[1].data = vlan_port_db_tmp->match_svlan;
                match_fields[1].mask = vlan_port_db_tmp->match_svlan_end;
            }
            else
            {
                match_fields[1].data = vlan_port_db_tmp->pkt_cvlan;
                match_fields[1].type = CTC_FIELD_KEY_CVLAN_ID;
            }
        }
        vlan_port.match_fields = &match_fields[0];
        vlan_port.gport = p_app_pon_master->nni_port[vdev_id];
        vlan_port.logic_port = p_app_pon_master->nni_logic_port[vdev_id];
        vlan_port.vlan_port_id = p_port_fid_db->vlan_port_id;
        vlan_port.fid = p_port_fid_db->fid;
        ctc_pon_create_vlan_port(&vlan_port);
    }
    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FID);
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_UNI);
    vlan_port.gport = vlan_port_db_tmp->port;
    vlan_port.vlan_port_id = vlan_port_db_tmp->vlan_port_id;
    vlan_port.fid = p_port_fid_db->fid;
    vlan_port.volt_tag_valid = 1;
    vlan_port.volt_tag = p_app_pon_master->vdev_base_vlan + vdev_id;
    ctc_pon_update_vlan_port(&vlan_port);
    if(vlan_port_db_tmp->p_gem_port_db != NULL)
    {
        if(vlan_port_db_tmp->p_gem_port_db->vn_tag || p_app_pon_master->p_port_pon[lport].vn_tag)
        {
            sal_memset(&vlan_port, 0, sizeof(vlan_port));
            CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_VN_TAG);
            CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_UNI);
            vlan_port.gport = vlan_port_db_tmp->port;
            vlan_port.vlan_port_id = vlan_port_db_tmp->vlan_port_id;
            vlan_port.volt_tag_valid = 1;
            vlan_port.volt_tag = p_app_pon_master->vdev_base_vlan + p_app_pon_master->vdev_num;
            vlan_port.logic_dest_port = p_app_pon_master->nni_logic_port[vdev_id];
            vlan_port.vn_tag = p_app_pon_master->p_port_pon[lport].vn_tag? p_app_pon_master->p_port_pon[lport].vn_tag:vlan_port_db_tmp->p_gem_port_db->vn_tag;
            ctc_pon_update_vlan_port(&vlan_port);
        }
    }

    _ctc_app_pon_remove_vlan(lchip, p_vlan_port, vlan_port_db_tmp);
    if (vlan_port_db_tmp->criteria == CTC_APP_PON_MATCH_PORT_FLEX ||
        vlan_port_db_tmp->criteria == CTC_APP_PON_MATCH_PORT_SVLAN_CVLAN)
    {
        ctc_hash_traverse(p_app_pon_master->gem_port_hash,
                          (spool_traversal_fn)_ctc_app_vlan_remove_pon_service_from_default_entry, (void*)vlan_port_db_tmp);
    }
    vlan_port_db_tmp->fid = p_port_fid_db->fid;
    p_app_pon_master->vlan_port_cnt[vlan_port_db_tmp->vdev_id]--;
    p_app_pon_master->vlan_port_cnt[vdev_id]++;
    vlan_port_db_tmp->vdev_id = vdev_id;
    _ctc_app_pon_add_vlan(lchip, p_vlan_port, vlan_port_db_tmp);
    sal_memset(&vlan_port_db, 0, sizeof(vlan_port_db));
    vlan_port_db.vlan_port_id = vlan_port_db_tmp->vlan_port_id;
    p_vlan_port_db = ctc_hash_lookup(p_app_pon_master->vlan_port_hash, &vlan_port_db);
    if(p_vlan_port_db != NULL)
    {
        p_vlan_port_db->fid = p_port_fid_db->fid;
        p_vlan_port_db->vdev_id = vdev_id;
    }

    return CTC_E_NONE;
}

int32
_ctc_app_pon_pkt_type_unmapping(uint32 gport, uint8 pkt_type, uint16 logic_port_in)
{
    uint32 acl_entry_id = ENCODE_APP_PON_ACL_ENTRY_ID(pkt_type, logic_port_in);
    
    ctc_acl_uninstall_entry(acl_entry_id);
    ctc_acl_remove_entry(acl_entry_id);

    return CTC_E_NONE;
}


/* add acl entry for ipv6/pppoe iloop*/
int32
_ctc_app_pon_pkt_type_mapping(uint32 gport, uint8 pkt_type, uint16 logic_port_in, uint32* logic_port_out)
{
    ctc_opf_t opf;
    uint32 logic_port = 0;
    int32 ret = CTC_E_NONE;
    uint32 gid = CTC_ACL_GROUP_ID_HASH_MAC;
    uint32 acl_entry_id = 0;
    uint32 field_cnt = 0;
    uint8 roll_back = 0;
    uint8 lchip = 0;
    ctc_acl_entry_t acl_entry;
    ctc_field_key_t key_field[3];
    ctc_field_port_t field_port;
    ctc_acl_property_t acl_prop;
    ctc_acl_field_action_t action_field[3];
    ctc_app_pon_uni_db_t* p_uni_port;
    
    if(pkt_type == 0)
    {
        return CTC_E_NONE;
    }
    _ctc_app_pon_get_uni_port(lchip, gport, &p_uni_port);
    acl_entry_id = ENCODE_APP_PON_ACL_ENTRY_ID(pkt_type, logic_port_in);
    logic_port = logic_port_out[pkt_type-1];
    if(!logic_port)
    {
        /*1. alloc acl logic port*/
        sal_memset(&opf, 0, sizeof(opf));
        opf.pool_type = CTC_OPF_VLAN_PORT;
        opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT;
        CTC_ERROR_RETURN(ctc_opf_alloc_offset(&opf, 1, &logic_port));
        roll_back = 1;
    }
    
    /*2. add acl entry*/
    sal_memset(&acl_entry, 0, sizeof(ctc_acl_entry_t));
    acl_entry.hash_field_sel_id = CTC_APP_PON_ACL_HASH_FIELD_SEL_ID;
    acl_entry.key_type = CTC_ACL_KEY_HASH_MAC;
    acl_entry.mode = 1;
    acl_entry.entry_id = acl_entry_id;
    ret = ctc_acl_add_entry(gid, &acl_entry);
    if(ret == CTC_E_EXIST)
    {
        return CTC_E_NONE;
    }
    else if(ret)
    {
        goto error1;
    }

    /*2.1 add acl key field*/
    key_field[0].type = CTC_FIELD_KEY_PORT;
    field_port.type = CTC_FIELD_PORT_TYPE_LOGIC_PORT;
    field_port.logic_port = logic_port_in;
    key_field[0].ext_data = &field_port;
    
    key_field[1].type = CTC_FIELD_KEY_ETHER_TYPE;
    key_field[1].data = (pkt_type == 1) ? 0x86dd : ((pkt_type == 2) ? 0x8863 : 0x8864);
    key_field[2].type = CTC_FIELD_KEY_HASH_VALID;
    key_field[2].data = 1;
    field_cnt = 3;
    CTC_ERROR_GOTO(ctc_acl_add_key_field_list(acl_entry_id, key_field, &field_cnt), ret, error2);

    /*2.2 add acl action field*/
    action_field[0].type = CTC_ACL_FIELD_ACTION_DENY_LEARNING;
    action_field[0].data0 = 1;
    action_field[1].type = CTC_ACL_FIELD_ACTION_LOGIC_PORT;
    action_field[1].data0 = logic_port;
    action_field[2].type = CTC_ACL_FIELD_ACTION_REDIRECT;
    action_field[2].data0 = p_uni_port->nh_iloop;
    field_cnt = 3;
    CTC_ERROR_GOTO(ctc_acl_add_action_field_list(acl_entry_id, action_field, &field_cnt), ret, error2);

    CTC_ERROR_GOTO(ctc_acl_install_entry(acl_entry_id), ret, error2);

    /*3. cfg port acl lookup*/
    sal_memset(&acl_prop, 0, sizeof(ctc_acl_property_t));// pon create
    acl_prop.acl_en = 1;
    acl_prop.direction = CTC_INGRESS;
    acl_prop.hash_field_sel_id = CTC_APP_PON_ACL_HASH_FIELD_SEL_ID;
    acl_prop.hash_lkup_type = CTC_ACL_HASH_LKUP_TYPE_L2;
    acl_prop.acl_priority = 0;
    CTC_SET_FLAG(acl_prop.flag, CTC_ACL_PROP_FLAG_USE_HASH_LKUP);
    CTC_ERROR_GOTO(ctc_port_set_acl_property(gport, &acl_prop), ret, error3);

    logic_port_out[pkt_type-1] = logic_port;
    return CTC_E_NONE;

error3:
    ctc_acl_uninstall_entry(acl_entry_id);
error2:
    ctc_acl_remove_entry(acl_entry_id);
error1:
    if(roll_back)
    {
        opf.pool_type = CTC_OPF_VLAN_PORT;
        opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT;
        ctc_opf_free_offset(&opf, 1, logic_port);
    }
    return ret;
}


int32
ctc_app_pon_create(uint8 lchip, ctc_app_pon_service_t* p_vlan_port)
{
    int32 ret = 0;
    uint8 onu_sevice_en = 0;
    uint16 pkt_svlan = 0;
    uint16 pkt_cvlan = 0;
    uint16 vdev_id = 0;
    uint32 logic_port = 0;
    uint32 vlan_port_id = 0;
    uint32 downlink_oun_nhid = 0;
    uint8 alloc_fid = 0;
    uint8 vlan_glb_vdev_en = 0 ;
    ctc_app_pon_gem_port_db_t gem_port_db;
    ctc_app_pon_gem_port_db_t* p_gem_port_db = NULL;
    ctc_app_pon_db_t* p_vlan_port_db = NULL;
    ctc_app_pon_db_t* vlan_port_db_tmp = NULL;
    ctc_opf_t opf;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;
    ctc_pon_vlan_port_t vlan_port;
    ctc_app_pon_fid_db_t port_fid_db;
    ctc_app_pon_fid_db_t* p_port_fid_db;
    ctc_field_key_t match_fields[20] ;
    ctc_vlan_mapping_t* p_vlan_mapping = NULL;

    /* CHECK */
    CTC_APP_PON_INIT_CHECK();
    CTC_PTR_VALID_CHECK(p_vlan_port);
    CTC_APP_PON_VLAN_ID_CHECK(p_vlan_port->match_svlan);
    CTC_APP_PON_VLAN_ID_CHECK(p_vlan_port->match_cvlan);
    CTC_APP_PON_VLAN_ID_CHECK(p_vlan_port->match_svlan_end);
    CTC_APP_PON_VLAN_ID_CHECK(p_vlan_port->match_cvlan_end);
    CTC_APP_PON_TUNNEL_VLAN_ID_CHECK(p_vlan_port->match_tunnel_value);
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_VLAN_PORT, p_vlan_port->port, p_vlan_port->vlan_port_id));

    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM_ST(criteria);
    CTC_APP_DBG_PARAM_ST(port);
    CTC_APP_DBG_PARAM_ST(match_tunnel_value);
    CTC_APP_DBG_PARAM_ST(match_svlan);
    CTC_APP_DBG_PARAM_ST(match_cvlan);
    CTC_APP_DBG_PARAM_ST(match_svlan_end);
    CTC_APP_DBG_PARAM_ST(match_cvlan_end);

    CTC_APP_DBG_PARAM_ST(ingress_vlan_action_set.svid);
    CTC_APP_DBG_PARAM_ST(ingress_vlan_action_set.new_svid);
    CTC_APP_DBG_PARAM_ST(ingress_vlan_action_set.cvid);
    CTC_APP_DBG_PARAM_ST(ingress_vlan_action_set.new_cvid);
    CTC_APP_DBG_PARAM_ST(ingress_vlan_action_set.scos);
    CTC_APP_DBG_PARAM_ST(ingress_vlan_action_set.new_scos);
    CTC_APP_DBG_PARAM_ST(ingress_vlan_action_set.ccos);
    CTC_APP_DBG_PARAM_ST(ingress_vlan_action_set.new_ccos);

    CTC_APP_DBG_PARAM_ST(egress_vlan_action_set.svid);
    CTC_APP_DBG_PARAM_ST(egress_vlan_action_set.new_svid);
    CTC_APP_DBG_PARAM_ST(egress_vlan_action_set.cvid);
    CTC_APP_DBG_PARAM_ST(egress_vlan_action_set.new_cvid);
    CTC_APP_DBG_PARAM_ST(egress_vlan_action_set.scos);
    CTC_APP_DBG_PARAM_ST(egress_vlan_action_set.new_scos);
    CTC_APP_DBG_PARAM_ST(egress_vlan_action_set.ccos);
    CTC_APP_DBG_PARAM_ST(egress_vlan_action_set.new_ccos);

    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    CTC_APP_PON_LOCK(lchip);
    /* Check pon port */
    CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_get_uni_port(lchip, p_vlan_port->port, &p_uni_port));
    p_vlan_port->match_pkt_type = (g_app_pon_mode && p_vlan_port->match_pkt_type < CTC_APP_PON_PKT_TYPE_MAX)? p_vlan_port->match_pkt_type : 0;
    
    if (0 == p_uni_port->isolated_id)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }
    vdev_id = p_uni_port->vdev_id;
    /* DB */
    if ((p_vlan_port->criteria == CTC_APP_PON_MATCH_PORT_TUNNEL_SVLAN_CVLAN)
        || (p_vlan_port->criteria == CTC_APP_PON_MATCH_PORT_TUNNEL_FLEX))
    {
        onu_sevice_en = 1; /*gem port onu base vlan edit*/
        sal_memset(&gem_port_db, 0, sizeof(ctc_app_pon_gem_port_db_t));
        gem_port_db.port = p_vlan_port->port;
        gem_port_db.tunnel_value = p_vlan_port->match_tunnel_value;
        p_gem_port_db = ctc_hash_lookup(p_app_pon_master->gem_port_hash, &gem_port_db);
        if (NULL == p_gem_port_db || 0 == p_app_pon_master->nni_port_cnt[p_gem_port_db->vdev_id])
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NOT_EXIST;
        }
        vdev_id = p_gem_port_db->vdev_id;
    }
    else if((p_vlan_port->criteria == CTC_APP_PON_MATCH_PORT_SVLAN_CVLAN)
        || (p_vlan_port->criteria == CTC_APP_PON_MATCH_PORT_FLEX))
    {
        if(p_app_pon_master->vdev_mode)
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NOT_SUPPORT;
        }
         onu_sevice_en = 0; /*port base vlan edit*/
         CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_PON_SERVICE);
    }
    else
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_SUPPORT;
    }

    MALLOC_POINTER(ctc_app_pon_db_t, vlan_port_db_tmp);
    if (NULL == vlan_port_db_tmp)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NO_MEMORY;
    }
    sal_memset(vlan_port_db_tmp, 0, sizeof(ctc_app_pon_db_t));
    vlan_port_db_tmp->criteria = p_vlan_port->criteria;
    vlan_port_db_tmp->port = p_vlan_port->port;
    vlan_port_db_tmp->tunnel_value = p_vlan_port->match_tunnel_value;
    vlan_port_db_tmp->match_svlan = p_vlan_port->match_svlan;
    vlan_port_db_tmp->match_svlan_end = p_vlan_port->match_svlan_end;
    vlan_port_db_tmp->match_cvlan = p_vlan_port->match_cvlan;
    vlan_port_db_tmp->match_cvlan_end = p_vlan_port->match_cvlan_end;
    vlan_port_db_tmp->match_pkt_type = p_vlan_port->match_pkt_type ;
    sal_memcpy(&vlan_port_db_tmp->flex_key, &p_vlan_port->flex_key, sizeof(vlan_port_db_tmp->flex_key));
    p_vlan_port_db = ctc_hash_lookup(p_app_pon_master->vlan_port_key_hash, &vlan_port_db_tmp);
    FREE_POINTER(vlan_port_db_tmp);

    if (NULL != p_vlan_port_db)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_ENTRY_EXIST;
    }

    MALLOC_POINTER(ctc_app_pon_db_t, p_vlan_port_db);
    if (NULL == p_vlan_port_db)
    {
        goto roll_back_0;
    }

     _ctc_app_pon_vlan_edit(lchip, p_vlan_port, &pkt_svlan, &pkt_cvlan);

    sal_memset(p_vlan_port_db, 0, sizeof(ctc_app_pon_db_t));
    /* OPF --> vlan port id, uni service and nni service vlan-port-id continues*/
    sal_memset(&opf, 0, sizeof(opf));
    opf.pool_type = CTC_OPF_VLAN_PORT;
    opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT_ID;
    CTC_ERROR_GOTO(ctc_opf_alloc_offset(&opf, 1, &vlan_port_id), ret, roll_back_0);
    CTC_APP_DBG_INFO("OPF vlan port id: %u\n", vlan_port_id);

    if (onu_sevice_en) /*First ONU service use the gem port logic port*/
    {
        CTC_ERROR_GOTO(_ctc_app_pon_alloc_nhid(lchip, &downlink_oun_nhid), ret, roll_back_1);
        sal_memset(&opf, 0, sizeof(opf));
        opf.pool_type = CTC_OPF_VLAN_PORT;
        opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT;
        CTC_ERROR_GOTO(ctc_opf_alloc_offset(&opf, 1, &logic_port), ret, roll_back_2);
        vlan_port.logic_port = logic_port;
        p_vlan_port_db->logic_port_b_en = 1;
        p_vlan_port_db->match_pkt_type = p_vlan_port->match_pkt_type ;
        CTC_APP_DBG_INFO("OPF vlan logic port: %u\n", vlan_port.logic_port);
        
        if(p_vlan_port_db->match_pkt_type)
        {
            CTC_ERROR_GOTO(_ctc_app_pon_pkt_type_mapping(p_vlan_port->port, p_vlan_port_db->match_pkt_type, p_gem_port_db->logic_port, p_gem_port_db->logic_port_ext), ret, roll_back_2);
        }
    }

    
    sal_memset(&port_fid_db, 0, sizeof(ctc_app_pon_fid_db_t));
    port_fid_db.vdev_id = vdev_id;
    port_fid_db.pkt_svlan = pkt_svlan;
    port_fid_db.pkt_cvlan = p_app_pon_master->fid_mode?0:pkt_cvlan;

    p_port_fid_db = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
    if(NULL == p_port_fid_db)
    {
        alloc_fid = 1;
    }
    CTC_ERROR_GOTO(ctc_spool_add(p_app_pon_master->fid_spool, &port_fid_db, NULL, &p_port_fid_db), ret, roll_back_2);

    if(CTC_IS_BIT_SET(p_app_pon_master->vlan_glb_vdev[p_port_fid_db->pkt_svlan/32], p_port_fid_db->pkt_svlan%32))
    {
        vlan_glb_vdev_en = 1;
    }

    vlan_port.criteria = CTC_PON_VLAN_PORT_MATCH_SVLAN_CVLAN;
    vlan_port.fid = p_port_fid_db->fid;
    sal_memset(&match_fields, 0, sizeof(ctc_field_key_t)*20);
    if(p_vlan_port->criteria == CTC_APP_PON_MATCH_PORT_TUNNEL_FLEX ||
        p_vlan_port->criteria == CTC_APP_PON_MATCH_PORT_FLEX)
    {
        CTC_ERROR_GOTO(_ctc_app_pon_flex_key_mapping(lchip, p_vlan_port, match_fields, &vlan_port), ret, roll_back_3);
    }
    else
    {
        CTC_ERROR_GOTO(_ctc_app_pon_match_key_mapping(lchip, p_vlan_port, match_fields, &vlan_port), ret, roll_back_3);
        if(p_vlan_port_db->match_pkt_type)
        {
            match_fields[vlan_port.fields_num].type = CTC_FIELD_KEY_PORT;
            match_fields[vlan_port.fields_num].data = p_gem_port_db->logic_port_ext[p_vlan_port_db->match_pkt_type-1];
            (vlan_port.fields_num)++;
        }
    }

    vlan_port.match_fields = &match_fields[0];
    vlan_port.vlan_port_id = vlan_port_id;
    vlan_port.igs_policer_id = p_vlan_port->ingress_policer_id;
    vlan_port.gport = p_vlan_port->port;
    vlan_port.tunnel_value = p_vlan_port->match_tunnel_value;
    /* vlan action map */
    _ctc_app_pon_vlan_mapping(lchip, p_vlan_port, p_vlan_mapping, &vlan_port.igs_vlan_action);
    _ctc_app_pon_scl_xlate_mapping(lchip, p_vlan_port, &vlan_port.egs_vlan_action);

    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_UNI);
    vlan_port.xlate_nhid = downlink_oun_nhid;
    vlan_port.volt_tag_valid = 1;
    vlan_port.volt_tag = p_app_pon_master->vdev_base_vlan + (vlan_glb_vdev_en? p_app_pon_master->vdev_num: p_port_fid_db->vdev_id);
    if(onu_sevice_en&&(p_gem_port_db->vn_tag || p_uni_port->vn_tag))
    {
        vlan_port.vn_tag = p_uni_port->vn_tag?p_uni_port->vn_tag:p_gem_port_db->vn_tag;
        vlan_port.volt_tag = p_app_pon_master->vdev_base_vlan + p_app_pon_master->vdev_num;
        vlan_port.logic_dest_port = p_app_pon_master->nni_logic_port[vdev_id];
    }
    /* create uni uplink service */
    CTC_ERROR_GOTO(ctc_pon_create_vlan_port(&vlan_port), ret, roll_back_3);

    if(alloc_fid)
    {
    /* create nni downlink service */
        CTC_ERROR_GOTO(_ctc_app_pon_create_downlink_service(lchip, p_vlan_port, p_port_fid_db), ret, roll_back_4);
    }
    /* add db */
    p_vlan_port_db->vdev_id = vdev_id;
    p_vlan_port_db->vlan_port_id = vlan_port_id;
    p_vlan_port_db->criteria = p_vlan_port->criteria;
    p_vlan_port_db->port = p_vlan_port->port;
    p_vlan_port_db->tunnel_value = p_vlan_port->match_tunnel_value;
    p_vlan_port_db->match_svlan = p_vlan_port->match_svlan;
    p_vlan_port_db->match_svlan_end = p_vlan_port->match_svlan_end;
    p_vlan_port_db->match_cvlan = p_vlan_port->match_cvlan;
    p_vlan_port_db->match_cvlan_end = p_vlan_port->match_cvlan_end;
    p_vlan_port_db->pkt_cvlan = pkt_cvlan;
    p_vlan_port_db->pkt_svlan = pkt_svlan;
    p_vlan_port_db->egress_policer_id = p_vlan_port->egress_policer_id;
    p_vlan_port_db->ingress_policer_id = p_vlan_port->ingress_policer_id;
    p_vlan_port_db->fid = p_port_fid_db->fid;
    p_vlan_port_db->logic_port = logic_port;
    p_vlan_port_db->xlate_nhid = downlink_oun_nhid;
    sal_memcpy(&p_vlan_port_db->flex_key, &p_vlan_port->flex_key, sizeof(ctc_acl_key_t));
    p_vlan_port_db->p_gem_port_db = p_gem_port_db;

    /*Add vlan*/
    CTC_ERROR_GOTO(_ctc_app_pon_add_vlan(lchip, p_vlan_port, p_vlan_port_db), ret, roll_back_4);

    ctc_hash_insert(p_app_pon_master->vlan_port_hash, p_vlan_port_db);
    ctc_hash_insert(p_app_pon_master->vlan_port_key_hash, p_vlan_port_db);
    p_app_pon_master->vlan_port_cnt[vdev_id]++;

    if(onu_sevice_en)
    {
        p_gem_port_db->ref_cnt++;
        ctc_l2_set_nhid_by_logic_port(logic_port, downlink_oun_nhid);
    }

    p_vlan_port->vlan_port_id = vlan_port_id;
    p_vlan_port->logic_port = p_vlan_port_db->logic_port;

    CTC_APP_PON_UNLOCK(lchip);

    return CTC_E_NONE;

   /*-----------------------------------------------------------
   *** rool back
   -----------------------------------------------------------*/
roll_back_4:
    if(alloc_fid)
    {
        _ctc_app_pon_destroy_downlink_service(lchip, p_port_fid_db->vlan_port_id, vdev_id, p_port_fid_db->pkt_svlan);
    }
    vlan_port.gport = p_vlan_port->port;
    vlan_port.vlan_port_id = vlan_port_id;
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_UNI);
    CTC_UNSET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_NNI);
    ctc_pon_destroy_vlan_port(&vlan_port);
roll_back_3:
    ctc_spool_remove(p_app_pon_master->fid_spool, &port_fid_db, NULL);

roll_back_2:
    if(logic_port)
    {
        opf.pool_type = CTC_OPF_VLAN_PORT;
        opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT;
        ctc_opf_free_offset(&opf, 1, logic_port);
    }
    if(downlink_oun_nhid)
    {
        _ctc_app_pon_free_nhid(lchip, downlink_oun_nhid);
    }

roll_back_1:
    opf.pool_type = CTC_OPF_VLAN_PORT;
    opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT_ID;
    ctc_opf_free_offset(&opf, 1, vlan_port_id);

roll_back_0:
    if(p_vlan_port_db)
    {
        mem_free(p_vlan_port_db);
    }
    p_vlan_port_db = NULL;
    CTC_APP_PON_UNLOCK(lchip);

    return ret;
}

int32
ctc_app_pon_destory(uint8 lchip, ctc_app_pon_service_t* p_vlan_port)
{
    uint32 logic_port = 0;
    uint32 nni_vlan_port_id = 0;
    ctc_app_pon_db_t vlan_port_db_tmp;
    ctc_app_pon_gem_port_db_t* p_gem_port_db = NULL;
    ctc_app_pon_db_t* p_vlan_port_db = NULL;
    ctc_opf_t opf;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;
    uint8 onu_sevice_en = 0;
    uint16 pkt_svlan = 0, pkt_cvlan = 0;
    uint16 vdev_id = 0;
    ctc_pon_vlan_port_t vlan_port;
    ctc_app_pon_fid_db_t port_fid_db;
    ctc_app_pon_fid_db_t* p_port_fid_db;

    /* CHECK */
    CTC_APP_PON_INIT_CHECK();
    CTC_PTR_VALID_CHECK(p_vlan_port);
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_VLAN_PORT, p_vlan_port->port, p_vlan_port->vlan_port_id));

    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM_ST(vlan_port_id);
    CTC_APP_DBG_PARAM_ST(criteria);
    CTC_APP_DBG_PARAM_ST(port);
    CTC_APP_DBG_PARAM_ST(match_tunnel_value);
    CTC_APP_DBG_PARAM_ST(match_svlan);
    CTC_APP_DBG_PARAM_ST(match_cvlan);
    CTC_APP_DBG_PARAM_ST(match_svlan_end);
    CTC_APP_DBG_PARAM_ST(match_cvlan_end);

    CTC_APP_PON_LOCK(lchip);

    /* DB */
    sal_memset(&vlan_port_db_tmp, 0, sizeof(vlan_port_db_tmp));
    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    sal_memset(&port_fid_db, 0, sizeof(port_fid_db));

    if ( p_vlan_port->vlan_port_id)
    {
        vlan_port_db_tmp.vlan_port_id = p_vlan_port->vlan_port_id;
        p_vlan_port_db = ctc_hash_lookup(p_app_pon_master->vlan_port_hash, &vlan_port_db_tmp);
    }
    else
    {
        vlan_port_db_tmp.criteria = p_vlan_port->criteria;
        vlan_port_db_tmp.port = p_vlan_port->port;
        vlan_port_db_tmp.tunnel_value = p_vlan_port->match_tunnel_value;
        vlan_port_db_tmp.match_svlan = p_vlan_port->match_svlan;
        vlan_port_db_tmp.match_svlan_end = p_vlan_port->match_svlan_end;
        vlan_port_db_tmp.match_cvlan = p_vlan_port->match_cvlan;
        vlan_port_db_tmp.match_cvlan_end = p_vlan_port->match_cvlan_end;
        vlan_port_db_tmp.match_pkt_type = (g_app_pon_mode && p_vlan_port->match_pkt_type < CTC_APP_PON_PKT_TYPE_MAX) ? p_vlan_port->match_pkt_type : 0;
        sal_memcpy(&vlan_port_db_tmp.flex_key, &p_vlan_port->flex_key, sizeof(vlan_port_db_tmp.flex_key));

        p_vlan_port_db = ctc_hash_lookup(p_app_pon_master->vlan_port_key_hash, &vlan_port_db_tmp);
        if(p_vlan_port_db)
        {
            vlan_port_db_tmp.vlan_port_id = p_vlan_port_db->vlan_port_id;
            p_vlan_port_db = ctc_hash_lookup(p_app_pon_master->vlan_port_hash, &vlan_port_db_tmp);
        }
    }

    if (NULL == p_vlan_port_db)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }

    _ctc_app_pon_get_uni_port(lchip, p_vlan_port_db->port, &p_uni_port);

    if ((p_vlan_port_db->criteria == CTC_APP_PON_MATCH_PORT_TUNNEL_SVLAN_CVLAN)
        || (p_vlan_port_db->criteria == CTC_APP_PON_MATCH_PORT_TUNNEL_FLEX))
    {
        onu_sevice_en = 1;
    }
    else if((p_vlan_port_db->criteria == CTC_APP_PON_MATCH_PORT_SVLAN_CVLAN)
        || (p_vlan_port_db->criteria == CTC_APP_PON_MATCH_PORT_FLEX))
    {
        onu_sevice_en = 0;
        CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_PON_SERVICE);
    }

    p_gem_port_db = p_vlan_port_db->p_gem_port_db;

    logic_port = p_vlan_port_db->logic_port;

    pkt_svlan = p_vlan_port_db->pkt_svlan;
    pkt_cvlan = p_vlan_port_db->pkt_cvlan;

    _ctc_app_pon_remove_vlan(lchip, p_vlan_port, p_vlan_port_db);

    vlan_port.vlan_port_id = p_vlan_port_db->vlan_port_id;
    vlan_port.gport = p_vlan_port_db->port;
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_UNI);
    ctc_pon_destroy_vlan_port(&vlan_port);

    /* Free fid */
    vdev_id = p_app_pon_master->vdev_mode? p_gem_port_db->vdev_id:p_uni_port->vdev_id;
    port_fid_db.vdev_id = vdev_id;
    port_fid_db.pkt_svlan = pkt_svlan;
    port_fid_db.pkt_cvlan = p_app_pon_master->fid_mode?0:pkt_cvlan;
    p_port_fid_db = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
    if(NULL != p_port_fid_db)
    {
        nni_vlan_port_id = p_port_fid_db->vlan_port_id;
        p_port_fid_db = NULL;
    }
    ctc_spool_remove(p_app_pon_master->fid_spool, &port_fid_db, NULL);
    p_port_fid_db = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
    if(NULL == p_port_fid_db)
    {
        _ctc_app_pon_destroy_downlink_service(lchip, nni_vlan_port_id, vdev_id, pkt_svlan);
    }

    if (onu_sevice_en)
    {
        ctc_l2_set_nhid_by_logic_port(logic_port, 0);
        _ctc_app_pon_free_nhid(lchip, p_vlan_port_db->xlate_nhid);
        if(p_vlan_port_db->logic_port_b_en)
        {
            /* Free opf */
            sal_memset(&opf, 0, sizeof(opf));
            opf.pool_type = CTC_OPF_VLAN_PORT;
            opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT;
            CTC_ERROR_RETURN_APP_PON_UNLOCK(ctc_opf_free_offset(&opf, 1, logic_port));
        }
        p_gem_port_db->ref_cnt--;
    }

    /* Free vlan port id*/
    sal_memset(&opf, 0, sizeof(opf));
    opf.pool_type = CTC_OPF_VLAN_PORT;
    opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT_ID;
    CTC_ERROR_RETURN_APP_PON_UNLOCK(ctc_opf_free_offset(&opf, 1, p_vlan_port_db->vlan_port_id));

    ctc_hash_remove(p_app_pon_master->vlan_port_hash, p_vlan_port_db);
    ctc_hash_remove(p_app_pon_master->vlan_port_key_hash, p_vlan_port_db);

    p_app_pon_master->vlan_port_cnt[vdev_id]--;

    CTC_APP_PON_UNLOCK(lchip);

    /* free memory */
    mem_free(p_vlan_port_db);
    p_vlan_port_db = NULL;

    return CTC_E_NONE;
}

int32
ctc_app_pon_get(uint8 lchip, ctc_app_pon_service_t* p_vlan_port)
{
    ctc_app_pon_db_t vlan_port_db_tmp;
    ctc_app_pon_db_t* p_vlan_port_db = NULL;
    ctc_pon_vlan_port_t vlan_port;
    uint32 vlan_port_id = 0;

    /* CHECK */
    CTC_APP_PON_INIT_CHECK();
    CTC_PTR_VALID_CHECK(p_vlan_port);
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_VLAN_PORT, p_vlan_port->port, p_vlan_port->vlan_port_id));

    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM_ST(vlan_port_id);
    CTC_APP_DBG_PARAM_ST(criteria);
    CTC_APP_DBG_PARAM_ST(port);
    CTC_APP_DBG_PARAM_ST(match_tunnel_value);
    CTC_APP_DBG_PARAM_ST(match_svlan);
    CTC_APP_DBG_PARAM_ST(match_cvlan);
    CTC_APP_DBG_PARAM_ST(match_svlan_end);
    CTC_APP_DBG_PARAM_ST(match_cvlan_end);

    CTC_APP_PON_LOCK(lchip);

    /* DB */
    sal_memset(&vlan_port_db_tmp, 0, sizeof(vlan_port_db_tmp));

    if (p_vlan_port->vlan_port_id)
    {
        vlan_port_id = p_vlan_port->vlan_port_id;
    }
    else
    {
        vlan_port_db_tmp.criteria = p_vlan_port->criteria;
        vlan_port_db_tmp.port = p_vlan_port->port;
        vlan_port_db_tmp.tunnel_value = p_vlan_port->match_tunnel_value;
        vlan_port_db_tmp.match_svlan = p_vlan_port->match_svlan;
        vlan_port_db_tmp.match_svlan_end = p_vlan_port->match_svlan_end;
        vlan_port_db_tmp.match_cvlan = p_vlan_port->match_cvlan;
        vlan_port_db_tmp.match_cvlan_end = p_vlan_port->match_cvlan_end;
        vlan_port_db_tmp.match_pkt_type = (g_app_pon_mode && p_vlan_port->match_pkt_type < CTC_APP_PON_PKT_TYPE_MAX) ? p_vlan_port->match_pkt_type : 0;
        sal_memcpy(&vlan_port_db_tmp.flex_key, &p_vlan_port->flex_key, sizeof(vlan_port_db_tmp.flex_key));

        p_vlan_port_db = ctc_hash_lookup(p_app_pon_master->vlan_port_key_hash, &vlan_port_db_tmp);

        if (NULL == p_vlan_port_db)
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NOT_EXIST;
        }
        vlan_port_id = p_vlan_port_db->vlan_port_id;
    }

    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    vlan_port.vlan_port_id = vlan_port_id;
    ctc_pon_get_vlan_port(&vlan_port);

    p_vlan_port->vlan_port_id = vlan_port.vlan_port_id;
    p_vlan_port->logic_port = vlan_port.logic_port;
    p_vlan_port->flex_nhid = vlan_port.xlate_nhid;
    CTC_APP_PON_UNLOCK(lchip);

    return CTC_E_NONE;
}

int32
ctc_app_pon_update(uint8 lchip, ctc_app_pon_service_t* p_vlan_port)
{
    ctc_app_pon_db_t vlan_port_db_tmp;
    ctc_app_pon_db_t* p_vlan_port_db = NULL;
    ctc_pon_vlan_port_t vlan_port;

    /* CHECK */
    CTC_APP_PON_INIT_CHECK();
    CTC_PTR_VALID_CHECK(p_vlan_port);
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_VLAN_PORT, p_vlan_port->port, p_vlan_port->vlan_port_id));

    /* Debug */
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM_ST(vlan_port_id);
    CTC_APP_DBG_PARAM_ST(criteria);
    CTC_APP_DBG_PARAM_ST(port);
    CTC_APP_DBG_PARAM_ST(match_tunnel_value);
    CTC_APP_DBG_PARAM_ST(match_svlan);
    CTC_APP_DBG_PARAM_ST(match_cvlan);
    CTC_APP_DBG_PARAM_ST(match_svlan_end);
    CTC_APP_DBG_PARAM_ST(match_cvlan_end);

    if (p_vlan_port->update_type == CTC_APP_PON_UPDATE_NONE)
    {
        return CTC_E_NOT_SUPPORT;
    }

    CTC_APP_PON_LOCK(lchip);
    /* DB */
    sal_memset(&vlan_port_db_tmp, 0, sizeof(vlan_port_db_tmp));
    sal_memset(&vlan_port, 0, sizeof(vlan_port));

    if (p_vlan_port->vlan_port_id)
    {
        vlan_port_db_tmp.vlan_port_id = p_vlan_port->vlan_port_id;
        p_vlan_port_db = ctc_hash_lookup(p_app_pon_master->vlan_port_hash, &vlan_port_db_tmp);
    }
    else
    {
        vlan_port_db_tmp.criteria = p_vlan_port->criteria;
        vlan_port_db_tmp.port = p_vlan_port->port;
        vlan_port_db_tmp.tunnel_value = p_vlan_port->match_tunnel_value;
        vlan_port_db_tmp.match_svlan = p_vlan_port->match_svlan;
        vlan_port_db_tmp.match_svlan_end = p_vlan_port->match_svlan_end;
        vlan_port_db_tmp.match_cvlan = p_vlan_port->match_cvlan;
        vlan_port_db_tmp.match_cvlan_end = p_vlan_port->match_cvlan_end;
        vlan_port_db_tmp.match_pkt_type = (g_app_pon_mode && p_vlan_port->match_pkt_type < CTC_APP_PON_PKT_TYPE_MAX) ? p_vlan_port->match_pkt_type : 0;
        sal_memcpy(&vlan_port_db_tmp.flex_key, &p_vlan_port->flex_key, sizeof(vlan_port_db_tmp.flex_key));
        p_vlan_port_db = ctc_hash_lookup(p_app_pon_master->vlan_port_key_hash, &vlan_port_db_tmp);
    }

    if (NULL == p_vlan_port_db)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }


    /*-----------------------------------------*/
    /*Ingress policetr*/
    if (p_vlan_port->update_type == CTC_APP_PON_UPDATE_IGS_POLICER)
    {
        vlan_port.vlan_port_id = p_vlan_port_db->vlan_port_id;
        ctc_pon_get_vlan_port(&vlan_port);
        vlan_port.igs_policer_id = p_vlan_port->ingress_policer_id;
        CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_IGS_POLICER);
        CTC_ERROR_RETURN_APP_PON_UNLOCK(ctc_pon_update_vlan_port(&vlan_port));
    }

    /*-----------------------------------------*/
    /*Egress policetr*/
    if (p_vlan_port->update_type == CTC_APP_PON_UPDATE_EGS_POLICER)
    {
        if (p_vlan_port->egress_policer_id == p_vlan_port_db->egress_policer_id)
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NONE;
        }

        CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_check_policer_id(lchip, p_vlan_port->egress_policer_id, CTC_EGRESS));

        p_vlan_port_db->egress_policer_id  = p_vlan_port->egress_policer_id;

    }
    CTC_APP_PON_UNLOCK(lchip);

    return CTC_E_NONE;
}

#define _____GEM_PORT_____ ""

int32
_ctc_app_pon_create_gem_port(uint8 lchip, ctc_app_pon_gem_port_t* p_gem_port,
                                     ctc_app_pon_gem_port_db_t* p_gem_port_db)
{
    uint16 lport = 0;
    int32 ret = 0;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;
    ctc_pon_gem_port_t gem_port;

    lport = CTC_MAP_GPORT_TO_LPORT(p_gem_port->port);
    p_uni_port = &p_app_pon_master->p_port_pon[lport];

    if(p_uni_port->backup_port_valid)
    {
        sal_memset(&gem_port, 0, sizeof(ctc_pon_gem_port_t));
        gem_port.gport = p_uni_port->backup_port;
        gem_port.tunnel_value = p_gem_port->tunnel_value;
        gem_port.pass_through_en = p_gem_port->pass_trough_en;
        gem_port.logic_port = p_gem_port_db->logic_port;
        gem_port.egs_service_id = p_gem_port_db->egs_service_id;
        CTC_ERROR_RETURN(ctc_pon_create_gem_port(&gem_port));
    }

    /* Create xlate nh */
    CTC_ERROR_GOTO(ctc_nh_get_l2uc(p_gem_port_db->port, CTC_NH_PARAM_BRGUC_SUB_TYPE_BASIC, &p_gem_port_db->pon_downlink_nhid), ret, roll_back_1);

    CTC_APP_DBG_INFO("add gem port pon downlink nhid: %u\n", p_gem_port_db->pon_downlink_nhid);

    /*PON port refcnt ++*/
    p_uni_port->ref_cnt++;

    return CTC_E_NONE;

   /*-----------------------------------------------------------
   *** rool back
   -----------------------------------------------------------*/
roll_back_1:
    ctc_pon_destroy_gem_port(&gem_port);
    return ret;
}

int32
_ctc_app_pon_destroy_gem_port(uint8 lchip, ctc_app_pon_gem_port_t* p_gem_port,
                                     ctc_app_pon_gem_port_db_t* p_gem_port_db)
{
    int32 ret = 0;
    uint16 lport = 0;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;
    ctc_pon_gem_port_t gem_port;

    lport = CTC_MAP_GPORT_TO_LPORT(p_gem_port->port);
    p_uni_port = &p_app_pon_master->p_port_pon[lport];

    if(p_uni_port->backup_port_valid)
    {
        sal_memset(&gem_port, 0, sizeof(ctc_pon_gem_port_t));
        gem_port.gport = p_uni_port->backup_port;
        gem_port.tunnel_value = p_gem_port->tunnel_value;
        gem_port.pass_through_en = p_gem_port->pass_trough_en;
        gem_port.logic_port = p_gem_port_db->logic_port;
        CTC_ERROR_RETURN(ctc_pon_destroy_gem_port(&gem_port));
    }

    /*PON port refcnt ++*/
    p_uni_port->ref_cnt--;

    return ret;
}

int32
ctc_app_pon_create_gem_port(uint8 lchip, ctc_app_pon_gem_port_t* p_gem_port)
{
    int32 ret = 0;
    uint32 logic_port = 0;
    ctc_opf_t opf;
    ctc_pon_gem_port_t gem_port;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;
    ctc_app_pon_gem_port_db_t gem_port_db;
    ctc_app_pon_gem_port_db_t* p_gem_port_db = NULL;

    /* CHECK */
    CTC_PTR_VALID_CHECK(p_gem_port);
    CTC_APP_PON_INIT_CHECK();
    CTC_APP_PON_TUNNEL_VLAN_ID_CHECK(p_gem_port->tunnel_value);
    CTC_APP_PON_VLAN_ID_CHECK(p_gem_port->vn_tag);
    CTC_APP_PON_VDEV_ID_CHECK(p_gem_port->vdev_id);

    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port",         p_gem_port->port);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "tunnel_value", p_gem_port->tunnel_value);

    CTC_APP_PON_LOCK(lchip);
    /* Check pon port */
    CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_get_uni_port(lchip, p_gem_port->port, &p_uni_port));
    if (0 == p_uni_port->isolated_id)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }

    /* DB */
    sal_memset(&gem_port_db, 0, sizeof(gem_port_db));
    gem_port_db.port = p_gem_port->port;
    gem_port_db.tunnel_value = p_gem_port->tunnel_value;
    p_gem_port_db = ctc_hash_lookup(p_app_pon_master->gem_port_hash, &gem_port_db);
    if (NULL != p_gem_port_db)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_EXIST;
    }

    MALLOC_POINTER(ctc_app_pon_gem_port_db_t, p_gem_port_db);
    if (NULL == p_gem_port_db)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NO_MEMORY;
    }
    /* OPF --> logicPort A */
    sal_memset(p_gem_port_db, 0, sizeof(ctc_app_pon_gem_port_db_t));
    sal_memset(&opf, 0, sizeof(opf));
    opf.pool_type = CTC_OPF_VLAN_PORT;
    opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT;
    CTC_ERROR_GOTO(ctc_opf_alloc_offset(&opf, 1, &logic_port), ret, free_meomory);
    p_gem_port_db->logic_port = logic_port;
    p_gem_port->logic_port = logic_port;
    CTC_APP_DBG_INFO("OPF gem logic port: %u\n", logic_port);

    sal_memset(&gem_port, 0, sizeof(ctc_pon_gem_port_t));
    gem_port.gport = p_gem_port->port;
    gem_port.tunnel_value = p_gem_port->tunnel_value;
    gem_port.pass_through_en = p_gem_port->pass_trough_en;
    gem_port.igs_policer_id = p_gem_port->ingress_policer_id;
    gem_port.logic_port = logic_port;
    gem_port.egs_service_id = p_gem_port->egress_service_id;
    CTC_ERROR_GOTO(ctc_pon_create_gem_port(&gem_port), ret, roll_back_0);

    /*Create gem port sevice*/
    p_gem_port_db->port = p_gem_port->port;
    p_gem_port_db->egs_service_id = p_gem_port->egress_service_id;
    CTC_ERROR_GOTO(_ctc_app_pon_create_gem_port(lchip, p_gem_port, p_gem_port_db), ret, roll_back_1);
    ctc_l2_set_nhid_by_logic_port(logic_port, p_gem_port_db->pon_downlink_nhid);
    p_gem_port_db->vdev_id = p_app_pon_master->vdev_mode ?p_gem_port->vdev_id:p_uni_port->vdev_id;
    p_gem_port_db->tunnel_value = p_gem_port->tunnel_value;
    p_gem_port_db->egress_policer_id = p_gem_port->egress_policer_id;
    p_gem_port_db->limit_num = CTC_APP_PON_LIMIT_NUM_DISABLE;
    p_gem_port_db->vn_tag = p_gem_port->vn_tag;
    ctc_hash_insert(p_app_pon_master->gem_port_hash, p_gem_port_db);
    p_app_pon_master->gem_port_cnt[p_gem_port_db->vdev_id]++;
    CTC_APP_PON_UNLOCK(lchip);

    return CTC_E_NONE;

   /*-----------------------------------------------------------
   *** rool back
   -----------------------------------------------------------*/
roll_back_1:
   ctc_pon_destroy_gem_port(&gem_port);
roll_back_0:
    ctc_opf_free_offset(&opf, 1, logic_port);

free_meomory:
    mem_free(p_gem_port_db);
    p_gem_port_db = NULL;
    CTC_APP_PON_UNLOCK(lchip);

    return ret;
}

int32
ctc_app_pon_destory_gem_port(uint8 lchip, ctc_app_pon_gem_port_t* p_gem_port)
{
    uint32 logic_port = 0;
    uint8 pkt_type_idx = 0 ;
    ctc_opf_t opf;
    ctc_pon_gem_port_t gem_port;
    ctc_app_pon_gem_port_db_t gem_port_db;
    ctc_app_pon_gem_port_db_t* p_gem_port_db = NULL;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;

    /* CHECK */
    CTC_PTR_VALID_CHECK(p_gem_port);
    CTC_APP_PON_INIT_CHECK();
    CTC_APP_PON_TUNNEL_VLAN_ID_CHECK(p_gem_port->tunnel_value);
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_GEM_PORT, p_gem_port->port, 0));

    /* Debug */
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port", p_gem_port->port);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "tunnel_value", p_gem_port->tunnel_value);

    CTC_APP_PON_LOCK(lchip);
    /* Check pon port */
    _ctc_app_pon_get_uni_port(lchip, p_gem_port->port, &p_uni_port);

    if (0 == p_uni_port->isolated_id)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }

    /* DB */
    sal_memset(&gem_port_db, 0, sizeof(gem_port_db));
    gem_port_db.port = p_gem_port->port;
    gem_port_db.tunnel_value = p_gem_port->tunnel_value;
    p_gem_port_db = ctc_hash_lookup(p_app_pon_master->gem_port_hash, &gem_port_db);
    if (NULL == p_gem_port_db)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }

    if (p_gem_port_db->ref_cnt)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return  CTC_E_IN_USE;
    }

    sal_memset(&gem_port, 0, sizeof(ctc_pon_gem_port_t));
    gem_port.gport = p_gem_port->port;
    gem_port.tunnel_value = p_gem_port->tunnel_value;
    ctc_pon_destroy_gem_port(&gem_port);

    logic_port = p_gem_port_db->logic_port;
    CTC_APP_DBG_INFO("Gem logic port: %u\n", logic_port);

    /*Create gem port sevice*/
    _ctc_app_pon_destroy_gem_port(lchip, p_gem_port, p_gem_port_db);

    ctc_l2_set_nhid_by_logic_port(logic_port, 0);

    /* Free OPF */
    sal_memset(&opf, 0, sizeof(opf));
    opf.pool_type = CTC_OPF_VLAN_PORT;
    opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT;
    ctc_opf_free_offset(&opf, 1, logic_port);
    for(pkt_type_idx = 0; pkt_type_idx < 3; pkt_type_idx++)
    {
        if(p_gem_port_db->logic_port_ext[pkt_type_idx])
        {
            ctc_opf_free_offset(&opf, 1, p_gem_port_db->logic_port_ext[pkt_type_idx]);
            _ctc_app_pon_pkt_type_unmapping(p_gem_port->port, pkt_type_idx+1, p_gem_port_db->logic_port);
        }
    }

    ctc_hash_remove(p_app_pon_master->gem_port_hash, p_gem_port_db);
    p_app_pon_master->gem_port_cnt[p_uni_port->vdev_id]--;
    CTC_APP_PON_UNLOCK(lchip);

    mem_free(p_gem_port_db);
    p_gem_port_db = NULL;

    return CTC_E_NONE;
}

int32
_ctc_app_pon_update_gem_port_vni_tag(ctc_app_pon_db_t* vlan_port_db_tmp, ctc_app_pon_gem_port_t* p_gem_port)
{
    ctc_pon_vlan_port_t vlan_port ;
    uint8 vdev_id = 0;
    uint16 lport = CTC_MAP_GPORT_TO_LPORT(p_gem_port->port);

    if(vlan_port_db_tmp->p_gem_port_db == NULL)
    {
        return 0;
    }

    if((vlan_port_db_tmp->port != p_gem_port->port) || (vlan_port_db_tmp->tunnel_value != p_gem_port->tunnel_value))
    {
        return 0;
    }
    vdev_id = p_app_pon_master->p_port_pon[lport].vdev_id;

    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_VN_TAG);
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_UNI);
    vlan_port.gport = vlan_port_db_tmp->port;
    vlan_port.vlan_port_id = vlan_port_db_tmp->vlan_port_id;
    vlan_port.fid = vlan_port_db_tmp->fid;
    vlan_port.volt_tag_valid = 1;
    vlan_port.volt_tag = p_gem_port->vn_tag?p_app_pon_master->vdev_base_vlan + p_app_pon_master->vdev_num:(p_app_pon_master->vdev_base_vlan+vdev_id);
    vlan_port.logic_dest_port = p_app_pon_master->nni_logic_port[vdev_id];
    vlan_port.vn_tag = p_gem_port->vn_tag;
    ctc_pon_update_vlan_port(&vlan_port);

    return CTC_E_NONE;

}

int32
_ctc_app_pon_update_gem_port_vdev_id(ctc_app_pon_db_t* vlan_port_db_tmp, ctc_app_pon_gem_port_t* p_gem_port)
{
    uint8 lchip= 0;
    uint16 lport = CTC_MAP_GPORT_TO_LPORT(p_gem_port->port);

    if(vlan_port_db_tmp->port != p_gem_port->port || vlan_port_db_tmp->tunnel_value != p_gem_port->tunnel_value)
    {
        return 0;
    }

    _ctc_app_pon_update_service_vdev_id(lchip, vlan_port_db_tmp, lport, p_gem_port->vdev_id);

    return CTC_E_NONE;

}



int32
ctc_app_pon_update_gem_port(uint8 lchip, ctc_app_pon_gem_port_t* p_gem_port)
{
    int32 ret = 0;
    ctc_pon_gem_port_t gem_port;
    ctc_app_pon_gem_port_db_t gem_port_db;
    ctc_app_pon_gem_port_db_t* p_gem_port_db = NULL;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;

    /* CHECK */
    CTC_PTR_VALID_CHECK(p_gem_port);
    CTC_APP_PON_INIT_CHECK();
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_GEM_PORT, p_gem_port->port, 0));
    if(CTC_APP_PON_GEM_PORT_UPDATE_VN_TAG == p_gem_port->update_type)
    {
        CTC_APP_PON_VLAN_ID_CHECK(p_gem_port->vn_tag);
    }
    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port", p_gem_port->port);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port", p_gem_port->tunnel_value);

    CTC_APP_PON_LOCK(lchip);
    /* Check pon port */
    CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_get_uni_port(lchip, p_gem_port->port, &p_uni_port));

    if (0 == p_uni_port->isolated_id)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }

    sal_memset(&gem_port, 0, sizeof(gem_port));
    gem_port.gport = p_gem_port->port;
    gem_port.tunnel_value = p_gem_port->tunnel_value;

    CTC_ERROR_RETURN_APP_PON_UNLOCK(ctc_pon_get_gem_port(&gem_port));

    sal_memset(&p_gem_port_db, 0, sizeof(p_gem_port_db));
    gem_port_db.port = p_gem_port->port;
    gem_port_db.tunnel_value= p_gem_port->tunnel_value;
    p_gem_port_db = ctc_hash_lookup(p_app_pon_master->gem_port_hash, &gem_port_db);
    if( NULL == p_gem_port_db)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }

    if(CTC_APP_PON_GEM_PORT_UPDATE_BIND_VLAN_PORT == p_gem_port->update_type ||
        CTC_APP_PON_GEM_PORT_UPDATE_UNBIND_VLAN_PORT == p_gem_port->update_type)
    {
        ctc_app_pon_db_t vlan_port_db;
        ctc_app_pon_db_t *p_vlan_port_db = NULL;
        ctc_l2dflt_addr_t l2dflt;
        ctc_mcast_nh_param_group_t mcast_group;
        uint16 mcast_group_id = 0;
        uint32 nh_id = 0;

        /* DB */
        sal_memset(&vlan_port_db, 0, sizeof(vlan_port_db));
        vlan_port_db.vlan_port_id = p_gem_port->vlan_port_id;

        p_vlan_port_db = ctc_hash_lookup(p_app_pon_master->vlan_port_hash, &vlan_port_db);

        if (NULL == p_vlan_port_db)
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NOT_EXIST;
        }

        if ((p_vlan_port_db->port != p_gem_port->port)
            || ((CTC_APP_PON_MATCH_PORT_SVLAN_CVLAN != p_vlan_port_db->criteria)
            && (CTC_APP_PON_MATCH_PORT_FLEX != p_vlan_port_db->criteria)))
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_INVALID_CONFIG;
        }

        /*Add/Remove vlan member*/
        sal_memset(&l2dflt, 0, sizeof(l2dflt));
        l2dflt.fid = p_vlan_port_db->fid;
        l2dflt.l2mc_grp_id = p_vlan_port_db->fid;
        l2dflt.logic_port = p_gem_port_db->logic_port;
        l2dflt.with_nh = 1;
        l2dflt.member.nh_id = p_gem_port_db->pon_downlink_nhid;

        CTC_APP_DBG_INFO("p_vlan_port_db->logic_port:%u\n", p_vlan_port_db->logic_port);

        if (CTC_APP_GEM_PORT_UPDATE_BIND_VLAN_PORT == p_gem_port->update_type )
        {
            CTC_ERROR_RETURN_APP_PON_UNLOCK(ctc_l2_add_port_to_default_entry(&l2dflt));
            CTC_APP_DBG_INFO("Group(%u) add ONU nhid: %u\n", l2dflt.l2mc_grp_id, l2dflt.member.nh_id);
            if(p_app_pon_master->mcast_tunnel_vlan == 0xffff)
            {
                sal_memset(&l2dflt, 0, sizeof(l2dflt));
                l2dflt.fid = p_vlan_port_db->fid;
                ctc_l2_get_default_entry_features(&l2dflt);
                mcast_group_id = ENCODE_MCAST_GROUP_ID(l2dflt.l2mc_grp_id, 1);
                ctc_nh_get_mcast_nh(mcast_group_id, &nh_id);
                sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
                mcast_group.mc_grp_id = mcast_group_id;
                mcast_group.opcode = CTC_NH_PARAM_MCAST_ADD_MEMBER;
                mcast_group.mem_info.ref_nhid = p_gem_port_db->pon_downlink_nhid;
                mcast_group.mem_info.logic_dest_port = p_gem_port_db->logic_port;
                mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
                ret = ctc_nh_update_mcast(nh_id, &mcast_group);
                if(ret < 0)
                {
                    sal_memset(&l2dflt, 0, sizeof(l2dflt));
                    l2dflt.fid = p_vlan_port_db->fid;
                    l2dflt.l2mc_grp_id = p_vlan_port_db->fid;
                    l2dflt.logic_port = p_gem_port_db->logic_port;
                    l2dflt.with_nh = 1;
                    l2dflt.member.nh_id = p_gem_port_db->pon_downlink_nhid;
                    ctc_l2_remove_port_from_default_entry(&l2dflt);
                }
            }
        }
        else
        {
            CTC_ERROR_RETURN_APP_PON_UNLOCK(ctc_l2_remove_port_from_default_entry(&l2dflt));
            CTC_APP_DBG_INFO("Group(%u) remove ONU nhid: %u\n", l2dflt.l2mc_grp_id, l2dflt.member.nh_id);
            if(p_app_pon_master->mcast_tunnel_vlan == 0xffff)
            {
                sal_memset(&l2dflt, 0, sizeof(l2dflt));
                l2dflt.fid = p_vlan_port_db->fid;
                ctc_l2_get_default_entry_features(&l2dflt);
                mcast_group_id = ENCODE_MCAST_GROUP_ID(l2dflt.l2mc_grp_id, 1);
                ctc_nh_get_mcast_nh(mcast_group_id, &nh_id);
                sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
                mcast_group.mc_grp_id = mcast_group_id;
                mcast_group.opcode = CTC_NH_PARAM_MCAST_DEL_MEMBER;
                mcast_group.mem_info.ref_nhid = p_gem_port_db->pon_downlink_nhid;
                mcast_group.mem_info.logic_dest_port = p_gem_port_db->logic_port;
                mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
                ctc_nh_update_mcast(nh_id, &mcast_group);
            }
        }
        CTC_APP_PON_UNLOCK(lchip);

        return ret;
    }
    else if(CTC_APP_PON_GEM_PORT_UPDATE_EGS_POLICER == p_gem_port->update_type)
    {
        if (p_gem_port->egress_policer_id == p_gem_port_db->egress_policer_id)
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NONE;
        }
        p_gem_port_db->egress_policer_id = p_gem_port->egress_policer_id;
    }
    else if (CTC_APP_PON_GEM_PORT_UPDATE_PASS_THROUGH_EN == p_gem_port->update_type)
    {
        gem_port.pass_through_en = p_gem_port->pass_trough_en;
        CTC_SET_FLAG(gem_port.flag, CTC_PON_GEM_PORT_FLAG_PASS_THROUGH_EN);
        CTC_ERROR_RETURN_APP_PON_UNLOCK(ctc_pon_update_gem_port(&gem_port));
        if(!p_gem_port->pass_trough_en)
        {
            ctc_l2_fdb_query_rst_t query_rst;
            ctc_l2_fdb_query_t Query;
            ctc_l2_fdb_query_t fdb_query;
            ctc_app_pon_fid_db_t port_fid_db;
            ctc_l2_flush_fdb_t Flush;
            uint8 index = 0;
            sal_memset(&query_rst, 0, sizeof(query_rst));
            sal_memset(&Query, 0, sizeof(Query));

            Query.query_type = CTC_L2_FDB_ENTRY_OP_BY_PORT;
            Query.use_logic_port = 1;
            Query.gport = p_gem_port_db->logic_port;
            Query.query_flag = CTC_L2_FDB_ENTRY_DYNAMIC;

            query_rst.buffer_len = sizeof(ctc_l2_addr_t) * 100;
            query_rst.buffer = (ctc_l2_addr_t*)mem_malloc(MEM_SYSTEM_MODULE, query_rst.buffer_len);
            if (NULL == query_rst.buffer)
            {
                CTC_APP_PON_UNLOCK(lchip);
                return CTC_E_NO_MEMORY;
            }
            do
            {
                query_rst.start_index = query_rst.next_query_index;
                ctc_l2_get_fdb_entry(&Query, &query_rst);
                for (index = 0; index < Query.count; index++)
                {
                    sal_memset(&port_fid_db, 0, sizeof(port_fid_db));
                    sal_memset(&fdb_query, 0, sizeof(fdb_query));
                    sal_memset(&Flush, 0, sizeof(Flush));
                    port_fid_db.fid = query_rst.buffer[index].fid;
                    ret = _ctc_app_pon_get_fid_by_fid(&port_fid_db);
                    if (ret && port_fid_db.is_pass_through)
                    {
                        Flush.flush_type = CTC_L2_FDB_ENTRY_OP_BY_PORT_VLAN;
                        Flush.flush_flag = CTC_L2_FDB_ENTRY_ALL;
                        Flush.gport = p_gem_port_db->logic_port;
                        Flush.fid = query_rst.buffer[index].fid;
                        Flush.use_logic_port = 1;
                        ctc_l2_flush_fdb(&Flush);
                        CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "fid: %d, logic port: %d \n", Flush.fid, Flush.gport);
                        _ctc_app_pon_remove_uplink_svlan_entry(lchip, p_gem_port_db->logic_port, &port_fid_db);
                    }
                    fdb_query.fid = query_rst.buffer[index].fid;
                    fdb_query.query_type = CTC_L2_FDB_ENTRY_OP_BY_VID;
                    fdb_query.query_flag = CTC_L2_FDB_ENTRY_DYNAMIC;
                    ctc_l2_get_fdb_count(&fdb_query);
                    if(ret && !fdb_query.count&&port_fid_db.is_pass_through)
                    {
                        _ctc_app_pon_remove_fdb_learn_with_def_fid(lchip, &port_fid_db);
                    }
                }
                sal_task_sleep(10);
            }
            while(query_rst.is_end == 0);

            mem_free(query_rst.buffer);
            query_rst.buffer = NULL;
        }

    }
    else if (CTC_APP_PON_GEM_PORT_UPDATE_VN_TAG == p_gem_port->update_type)
    {
        if(p_gem_port_db->vn_tag == p_gem_port->vn_tag || p_uni_port->vn_tag)
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NONE;
        }
        ctc_hash_traverse(p_app_pon_master->vlan_port_key_hash,
                          (spool_traversal_fn)_ctc_app_pon_update_gem_port_vni_tag, p_gem_port);
        p_gem_port_db->vn_tag = p_gem_port->vn_tag;
    }
    else if (CTC_APP_PON_GEM_PORT_UPDATE_VDEVICE_ID == p_gem_port->update_type)
    {
        if(!p_app_pon_master->vdev_mode)
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NOT_SUPPORT;
        }
        if(p_gem_port_db->vdev_id == p_gem_port->vdev_id)
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NONE;
        }
        ctc_hash_traverse(p_app_pon_master->vlan_port_key_hash,
                          (spool_traversal_fn)_ctc_app_pon_update_gem_port_vdev_id, p_gem_port);
        p_app_pon_master->gem_port_cnt[p_gem_port_db->vdev_id]--;
        p_gem_port_db->vdev_id = p_gem_port->vdev_id;
        p_app_pon_master->gem_port_cnt[p_gem_port->vdev_id]++;
    }
    else if (CTC_APP_PON_GEM_PORT_UPDATE_EGS_SERVICE == p_gem_port->update_type)
    {
        gem_port.egs_service_id = p_gem_port->egress_service_id;
        CTC_ERROR_RETURN_APP_PON_UNLOCK(ctc_pon_update_gem_port(&gem_port));
    }
    CTC_APP_PON_UNLOCK(lchip);

    return CTC_E_NONE;
}

int32
ctc_app_pon_get_gem_port(uint8 lchip, ctc_app_pon_gem_port_t* p_gem_port)
{
    ctc_pon_gem_port_t gem_port;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;

    /* CHECK */
    CTC_PTR_VALID_CHECK(p_gem_port);
    CTC_APP_PON_INIT_CHECK();
    CTC_APP_PON_TUNNEL_VLAN_ID_CHECK(p_gem_port->tunnel_value);
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_GEM_PORT, p_gem_port->port, 0));

    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port", p_gem_port->port);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port", p_gem_port->tunnel_value);

    CTC_APP_PON_LOCK(lchip);
    /* Check pon port */
    CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_get_uni_port(lchip, p_gem_port->port, &p_uni_port));

    if (0 == p_uni_port->isolated_id)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }

    sal_memset(&gem_port, 0, sizeof(gem_port));
    gem_port.gport = p_gem_port->port;
    gem_port.tunnel_value = p_gem_port->tunnel_value;
    CTC_ERROR_RETURN_APP_PON_UNLOCK(ctc_pon_get_gem_port(&gem_port));
    p_gem_port->logic_port = gem_port.logic_port;
    CTC_APP_PON_UNLOCK(lchip);

    return CTC_E_NONE;
}

#define _____UNI_PORT_____ ""

/*
Each pon port: xlate nhid
*/
int32
_ctc_app_pon_create_mc_gem_port(uint8 lchip, uint32 port)
{
    int32 ret = 0;
    uint16 lport = 0;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;
    ctc_vlan_edit_nh_param_t gem_xlate_nh;
    ctc_pon_gem_port_t gem_port;

    lport = CTC_MAP_GPORT_TO_LPORT(port);
    p_uni_port = &p_app_pon_master->p_port_pon[lport];

    CTC_ERROR_RETURN(_ctc_app_pon_alloc_nhid(lchip, &p_uni_port->mc_xlate_nhid));

    /* Create xlate nh */
    sal_memset(&gem_xlate_nh, 0, sizeof(gem_xlate_nh));
    gem_xlate_nh.gport_or_aps_bridge_id = port;
    gem_xlate_nh.vlan_edit_info.svlan_edit_type = CTC_VLAN_EGRESS_EDIT_INSERT_VLAN;
    gem_xlate_nh.vlan_edit_info.cvlan_edit_type = CTC_VLAN_EGRESS_EDIT_KEEP_VLAN_UNCHANGE;
    if(p_app_pon_master->mcast_tunnel_vlan == 0 || p_app_pon_master->mcast_tunnel_vlan == 0xffff)
    {
        gem_xlate_nh.vlan_edit_info.output_svid = CTC_APP_PON_MCAST_TUNNEL_ID;
    }
    else
    {
        gem_xlate_nh.vlan_edit_info.output_svid = p_app_pon_master->mcast_tunnel_vlan;
    }
    CTC_SET_FLAG(gem_xlate_nh.vlan_edit_info.edit_flag, CTC_VLAN_EGRESS_EDIT_OUPUT_SVID_VALID);
    CTC_SET_FLAG(gem_xlate_nh.vlan_edit_info.flag, CTC_VLAN_NH_LENGTH_ADJUST_EN); /*Use Resever offset*/

    CTC_APP_DBG_INFO("nh-mc xlate nhid: %u\n", p_uni_port->mc_xlate_nhid);
    CTC_ERROR_GOTO(ctc_nh_add_xlate(p_uni_port->mc_xlate_nhid, &gem_xlate_nh), ret, roll_back_0);
    /*
    gem_xlate_nh.vlan_edit_info.output_svid = p_app_pon_master->bcast_tunnel_vlan;
    CTC_SET_FLAG(gem_xlate_nh.vlan_edit_info.edit_flag, CTC_VLAN_EGRESS_EDIT_REPLACE_SVLAN_COS);
    gem_xlate_nh.vlan_edit_info.stag_cos = 0;
    CTC_APP_DBG_INFO("nh-bc xlate nhid: %u\n", p_uni_port->bc_xlate_nhid);
    CTC_ERROR_GOTO(ctc_nh_add_xlate(p_uni_port->bc_xlate_nhid, &gem_xlate_nh), ret, roll_back_1);*/

    sal_memset(&gem_port, 0, sizeof(ctc_pon_gem_port_t));
    gem_port.gport = port;
    gem_port.tunnel_value = p_app_pon_master->bcast_tunnel_vlan;
    gem_port.logic_port = p_app_pon_master->bcast_value_logic_port;
    CTC_SET_FLAG(gem_port.flag, CTC_PON_GEM_PORT_FLAG_FLOODING);
    CTC_ERROR_GOTO(ctc_pon_create_gem_port(&gem_port), ret, roll_back_1);

    return CTC_E_NONE;

    /*-----------------------------------------------------------
    *** rool back
    -----------------------------------------------------------*/
roll_back_1:
    ctc_nh_remove_xlate(p_uni_port->mc_xlate_nhid);
roll_back_0:
    _ctc_app_pon_free_nhid(lchip, p_uni_port->mc_xlate_nhid);

    return ret;
}

/*
Each pon port: xlate nhid
*/
int32
_ctc_app_pon_destroy_mc_gem_port(uint8 lchip, uint32 port)
{
    int32 ret = 0;
    uint16 lport = 0;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;
    ctc_pon_gem_port_t gem_port;

    lport = CTC_MAP_GPORT_TO_LPORT(port);
    p_uni_port = &p_app_pon_master->p_port_pon[lport];

    /* Remove  xlate nh */
    ctc_nh_remove_xlate(p_uni_port->mc_xlate_nhid);

    _ctc_app_pon_free_nhid(lchip, p_uni_port->mc_xlate_nhid);

    sal_memset(&gem_port, 0, sizeof(ctc_pon_gem_port_t));
    gem_port.gport = port;
    gem_port.tunnel_value = p_app_pon_master->bcast_tunnel_vlan;
    CTC_SET_FLAG(gem_port.flag, CTC_PON_GEM_PORT_FLAG_FLOODING);
    ctc_pon_destroy_gem_port(&gem_port);

    p_uni_port->mc_xlate_nhid = 0;

    return ret;
}

int32
_ctc_app_pon_update_pon_vdev_id(ctc_app_pon_db_t* vlan_port_db_tmp, uint32* uni_port)
{
    uint8 lchip= 0;
    uint16 lport = CTC_MAP_GPORT_TO_LPORT(*uni_port);

    if(vlan_port_db_tmp->port != *uni_port)
    {
        return 0;
    }

    _ctc_app_pon_update_service_vdev_id(lchip, vlan_port_db_tmp, lport, p_app_pon_master->p_port_pon[lport].vdev_id);

    return CTC_E_NONE;

}

int32
_ctc_app_pon_update_vdevice_gemport_cnt(ctc_app_pon_gem_port_db_t* gem_port_db_tmp, uint32* uni_port)
{
    uint8 vdev_id = 0;
    uint16 lport = CTC_MAP_GPORT_TO_LPORT(*uni_port);

    if(gem_port_db_tmp->port != *uni_port)
    {
        return 0;
    }

    vdev_id = p_app_pon_master->p_port_pon[lport].vdev_id;

    p_app_pon_master->gem_port_cnt[gem_port_db_tmp->vdev_id]--;
    gem_port_db_tmp->vdev_id = vdev_id;
    p_app_pon_master->gem_port_cnt[vdev_id]++;


    return CTC_E_NONE;

}

int32
_ctc_app_pon_update_uni_default_entry(uint8 lchip, uint8 is_update, uint8 is_del, ctc_app_pon_uni_t* p_uni, ctc_app_pon_uni_db_t* p_uni_port)
{
    uint8 is_remove = 0;
    int32 ret = 0;
    uint32 mcast_group_id = 0;
    uint32 nh_id = 0;
    ctc_mcast_nh_param_group_t mcast_group;

    is_remove = is_update | is_del;
    mcast_group_id = ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[p_uni_port->vdev_id], 4);
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.mc_grp_id = mcast_group_id;
    mcast_group.opcode = is_remove?CTC_NH_PARAM_MCAST_DEL_MEMBER:CTC_NH_PARAM_MCAST_ADD_MEMBER;
    mcast_group.mem_info.destid = p_uni->port;
    mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_BRGMC_LOCAL;
    mcast_group.mem_info.logic_dest_port = p_app_pon_master->bcast_value_logic_port;
    nh_id = p_app_pon_master->default_unknown_bcast_nhid[p_uni_port->vdev_id];
    CTC_ERROR_RETURN(ctc_nh_update_mcast(nh_id, &mcast_group));
    nh_id = p_app_pon_master->glb_unknown_bcast_nhid;
    ctc_nh_update_mcast(nh_id, &mcast_group);
    if(is_update)
    {
        mcast_group_id = ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[p_uni->vdev_id], 4);
        mcast_group.mc_grp_id = mcast_group_id;
        mcast_group.opcode =CTC_NH_PARAM_MCAST_ADD_MEMBER;
        nh_id = p_app_pon_master->default_unknown_bcast_nhid[p_uni->vdev_id];
        ctc_nh_update_mcast(nh_id, &mcast_group);
        nh_id = p_app_pon_master->glb_unknown_bcast_nhid;
        ctc_nh_update_mcast(nh_id, &mcast_group);
    }

    /*Add MC member*/
    if (0 == p_app_pon_master->unknown_mcast_drop_en[p_uni_port->vdev_id])
    {
        mcast_group_id = ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[p_uni_port->vdev_id], 3);
        sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
        mcast_group.mc_grp_id = mcast_group_id;
        mcast_group.opcode = is_remove?CTC_NH_PARAM_MCAST_DEL_MEMBER:CTC_NH_PARAM_MCAST_ADD_MEMBER;
        mcast_group.mem_info.ref_nhid = p_uni_port->mc_xlate_nhid;
        mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
        nh_id = p_app_pon_master->default_unknown_mcast_nhid[p_uni_port->vdev_id];
        CTC_ERROR_GOTO(ctc_nh_update_mcast( nh_id, &mcast_group),ret,roll_back_0);
        nh_id = p_app_pon_master->glb_unknown_mcast_nhid;
        ctc_nh_update_mcast(nh_id, &mcast_group);
    }
    if(is_update && 0 == p_app_pon_master->unknown_mcast_drop_en[p_uni->vdev_id])
    {
        mcast_group_id = ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[p_uni->vdev_id], 3);
        sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
        mcast_group.mc_grp_id = mcast_group_id;
        mcast_group.opcode = CTC_NH_PARAM_MCAST_ADD_MEMBER;
        mcast_group.mem_info.ref_nhid = p_uni_port->mc_xlate_nhid;
        mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
        nh_id = p_app_pon_master->default_unknown_mcast_nhid[p_uni->vdev_id];
        ctc_nh_update_mcast( nh_id, &mcast_group);
        nh_id = p_app_pon_master->glb_unknown_mcast_nhid;
        ctc_nh_update_mcast(nh_id, &mcast_group);
    }

    return CTC_E_NONE;

roll_back_0:
    mcast_group_id = ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[p_uni->vdev_id], 4);
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.mc_grp_id = mcast_group_id;
    mcast_group.opcode = CTC_NH_PARAM_MCAST_DEL_MEMBER;
    mcast_group.mem_info.destid = p_uni->port;
    mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_BRGMC_LOCAL;
    mcast_group.mem_info.logic_dest_port = p_app_pon_master->bcast_value_logic_port;
    nh_id = p_app_pon_master->default_unknown_bcast_nhid[p_uni->vdev_id];
    ctc_nh_update_mcast(nh_id, &mcast_group);
    nh_id = p_app_pon_master->glb_unknown_bcast_nhid;
    ctc_nh_update_mcast(nh_id, &mcast_group);

    return ret;

}

int32
ctc_app_pon_create_uni(uint8 lchip, ctc_app_pon_uni_t* p_uni)
{
    int32 ret = 0;
    uint8 is_update = 0;
    uint8 is_internal = 0;
    uint32 value = 0;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;
    ctc_port_restriction_t isolation;
    ctc_port_isolation_t port_isolation;
    ctc_pon_vlan_port_t vlan_port;
    ctc_pon_port_cfg_t cfg;
    ctc_internal_port_assign_para_t port_assign;

    /* CHECK */
    CTC_PTR_VALID_CHECK(p_uni);
    CTC_APP_PON_INIT_CHECK();
    CTC_APP_PON_VDEV_ID_CHECK(p_uni->vdev_id);
    CTC_APP_PON_VLAN_ID_CHECK(p_uni->vn_tag);
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_UNI_PORT, p_uni->port, 0));
    if(p_uni->backup_port_valid)
    {
        CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_UNI_PORT, p_uni->backup_port, 0));
        CTC_ERROR_RETURN(ctc_port_get_capability(p_uni->backup_port, CTC_PORT_CAP_TYPE_MAC_ID, &value));
    }

    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "vDev id",      p_uni->vdev_id);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port",         p_uni->port);

    CTC_APP_PON_LOCK(lchip);
    CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_get_uni_port(lchip, p_uni->port, &p_uni_port));
    ret = ctc_port_get_capability(p_uni->port, CTC_PORT_CAP_TYPE_MAC_ID, &value);
    if(ret < 0)
    {
        ret = 0;
        is_internal = 1;
    }
    if (0 != p_uni_port->isolated_id)
    {
        if(p_uni_port->vdev_id != p_uni->vdev_id && !p_app_pon_master->vdev_mode)
        {
            is_update = 1;
        }
        else
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_EXIST;
        }
    }
    if(is_update && p_uni->backup_port_valid)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_SUPPORT;
    }
    /***********************************************/
    /** Alloc new uni port isolated id*/
    if(!is_update)
    {
        /***********************************************/
        /** ponit the uni port vdev_id*/
        p_uni_port->vdev_id = p_uni->vdev_id;
    }

    /***********************************************/
    /** Uni port property*/
    sal_memset(&cfg, 0, sizeof(cfg));
    cfg.value = 1;
    cfg.type = CTC_PON_PORT_CFG_UNI_EN;
    cfg.criteria = CTC_PON_VLAN_PORT_MATCH_SVLAN_CVLAN;
    CTC_ERROR_GOTO(ctc_pon_set_port_propery(p_uni->port, &cfg), ret, roll_back_0);
    /*cfg.value = p_uni->vn_tag;
    cfg.type = CTC_PON_PORT_CFG_UNI_VNI_TAG;
    CTC_ERROR_GOTO(ctc_pon_set_port_propery(p_uni->port, &cfg), ret, roll_back_0);*/
    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    vlan_port.gport = p_uni->port;
    vlan_port.fid = p_app_pon_master->vdev_mode?p_app_pon_master->glb_default_bcast_fid:p_app_pon_master->default_bcast_fid[p_uni->vdev_id];
    vlan_port.flag |= CTC_PON_VLAN_PORT_FLAG_DEFAULT_SERVICE;
    vlan_port.volt_tag_valid = p_app_pon_master->vdev_mode? 0:1;
    vlan_port.volt_tag = p_app_pon_master->vdev_base_vlan + p_uni->vdev_id;
    CTC_ERROR_GOTO(ctc_pon_create_vlan_port(&vlan_port), ret, roll_back_1);

    if(!is_update)
    {
        /***********************************************/
        /** BC/MC PORT property*/
        CTC_ERROR_GOTO(_ctc_app_pon_create_mc_gem_port(lchip, p_uni->port), ret, roll_back_1);
    }

    /*Add BC member*/
    if(p_app_pon_master->mcast_tunnel_vlan != 0xffff && !is_internal && !p_app_pon_master->vdev_mode)
    {
        CTC_ERROR_GOTO(_ctc_app_pon_update_uni_default_entry(lchip, is_update, 0, p_uni, p_uni_port), ret, roll_back_2);
    }

    if(is_update)
    {
        p_uni_port->vdev_id = p_uni->vdev_id;
        ctc_hash_traverse(p_app_pon_master->vlan_port_key_hash,
                          (spool_traversal_fn)_ctc_app_pon_update_pon_vdev_id, &(p_uni->port));
        ctc_hash_traverse(p_app_pon_master->gem_port_hash,
                          (spool_traversal_fn)_ctc_app_pon_update_vdevice_gemport_cnt, &(p_uni->port));
        p_uni->mc_nhid = p_uni_port->mc_xlate_nhid;
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NONE;
    }

    /***********************************************/
    /** PORT ISOLATION*/
    p_uni_port->isolated_id = 1;
    sal_memset(&isolation, 0, sizeof(isolation));
    isolation.dir = CTC_EGRESS;
    isolation.isolated_id  = p_uni_port->isolated_id;
    isolation.mode = CTC_PORT_RESTRICTION_DISABLE;
    isolation.type = CTC_PORT_ISOLATION_ALL;
    CTC_ERROR_GOTO(ctc_port_set_restriction(p_uni->port, &isolation), ret, roll_back_4);
    isolation.dir = CTC_INGRESS;
    CTC_ERROR_GOTO(ctc_port_set_restriction(p_uni->port, &isolation), ret, roll_back_5);

    sal_memset(&port_isolation, 0, sizeof(ctc_port_isolation_t));
    port_isolation.gport = p_uni_port->isolated_id;
    port_isolation.use_isolation_id = 1;
    port_isolation.pbm[0] = 1<<(p_uni_port->isolated_id);
    port_isolation.isolation_pkt_type = CTC_PORT_ISOLATION_ALL;
    CTC_ERROR_GOTO(ctc_port_set_isolation(lchip, &port_isolation), ret, roll_back_6);

    /***********************************************/
    /** enable uni port mux gem */
    if(p_uni->backup_port_valid)
    {
        ctc_pon_set_port_propery(p_uni->backup_port, &cfg);
        p_uni_port->backup_port = p_uni->backup_port;
        p_uni_port->backup_port_valid = p_uni->backup_port_valid;
    }

    p_uni->mc_nhid = p_uni_port->mc_xlate_nhid;
    p_uni_port->vn_tag = p_uni->vn_tag;
    
    /***********************************************/
    /** alloc iloop port*/
    if(g_app_pon_mode == 1)
    {
        uint8 gchip_id = 0;        
        ctc_loopback_nexthop_param_t nh_param;
        ctc_port_scl_property_t scl_prop;
        
        /*1. create iloop port for acl action*/
        _ctc_app_pon_alloc_nhid(lchip, &p_uni_port->nh_iloop);
        sal_memset(&port_assign, 0 , sizeof(port_assign));
        ctc_get_gchip_id(lchip, &gchip_id);
        port_assign.type = CTC_INTERNAL_PORT_TYPE_ILOOP;
        port_assign.gchip = gchip_id;
        CTC_ERROR_GOTO(ctc_alloc_internal_port(&port_assign), ret, roll_back_7);

        sal_memset(&nh_param, 0 , sizeof(nh_param));
        nh_param.lpbk_lport = port_assign.inter_port;
        CTC_ERROR_GOTO(ctc_nh_add_iloop(p_uni_port->nh_iloop, &nh_param), ret, roll_back_8);

        /*2. enable pon port scl0 lookup*/
        sal_memset(&scl_prop, 0, sizeof(scl_prop));
        scl_prop.direction = CTC_INGRESS;
        scl_prop.tcam_type = CTC_PORT_IGS_SCL_TCAM_TYPE_RESOLVE_CONFLICT;
        scl_prop.hash_vlan_range_dis = 1;
        scl_prop.scl_id = 0;
        scl_prop.hash_type = CTC_PORT_IGS_SCL_HASH_TYPE_L2;
        scl_prop.action_type = CTC_PORT_SCL_ACTION_TYPE_FLOW;
        CTC_ERROR_GOTO(ctc_port_set_scl_property(p_uni->port, &scl_prop), ret, roll_back_9);
        CTC_ERROR_GOTO(ctc_port_set_property(p_uni->port, CTC_PORT_PROP_SCL_HASH_FIELD_SEL_ID, 3), ret, roll_back_9);
        if(p_uni->backup_port_valid)
        {
            CTC_ERROR_GOTO(ctc_port_set_scl_property(p_uni->backup_port, &scl_prop), ret, roll_back_9);
            CTC_ERROR_GOTO(ctc_port_set_property(p_uni->backup_port, CTC_PORT_PROP_SCL_HASH_FIELD_SEL_ID, 3), ret, roll_back_9);
        }

        /*3. enable iloop port scl1 lookup*/
        scl_prop.scl_id = 1;
        scl_prop.hash_type = CTC_PORT_IGS_SCL_HASH_TYPE_PORT_2VLAN;
        scl_prop.action_type = CTC_PORT_SCL_ACTION_TYPE_SCL;
        scl_prop.use_logic_port_en = 1;
        CTC_ERROR_GOTO(ctc_port_set_scl_property(CTC_MAP_LPORT_TO_GPORT(gchip_id, nh_param.lpbk_lport), &scl_prop), ret, roll_back_9);
        CTC_ERROR_GOTO(ctc_port_set_property(CTC_MAP_LPORT_TO_GPORT(gchip_id, nh_param.lpbk_lport), CTC_PORT_PROP_GPORT, p_uni->port), ret, roll_back_9);
    }
    CTC_APP_PON_UNLOCK(lchip);

    return CTC_E_NONE;
roll_back_9:
    ctc_nh_remove_iloop(p_uni_port->nh_iloop);
roll_back_8:
    ctc_free_internal_port(&port_assign);
roll_back_7:
    sal_memset(&port_isolation, 0, sizeof(ctc_port_isolation_t));
    port_isolation.gport = p_uni_port->isolated_id;
    port_isolation.use_isolation_id = 0;
    port_isolation.pbm[0] = 0;
    port_isolation.isolation_pkt_type = CTC_PORT_ISOLATION_ALL;
    ctc_port_set_isolation(lchip, &port_isolation);
roll_back_6:
    sal_memset(&isolation, 0, sizeof(isolation));
    isolation.dir = CTC_INGRESS;
    isolation.isolated_id  = 0;
    isolation.mode = CTC_PORT_RESTRICTION_PORT_ISOLATION;
    isolation.type = CTC_PORT_ISOLATION_ALL;
    ctc_port_set_restriction(p_uni->port, &isolation);

roll_back_5:
    sal_memset(&isolation, 0, sizeof(isolation));
    isolation.dir = CTC_EGRESS;
    isolation.isolated_id  = 0;
    isolation.mode = CTC_PORT_RESTRICTION_PORT_ISOLATION;
    isolation.type = CTC_PORT_ISOLATION_ALL;
    ctc_port_set_restriction(p_uni->port, &isolation);
    p_uni_port->isolated_id = 0;

roll_back_4:
    if(p_app_pon_master->mcast_tunnel_vlan != 0xffff && !is_internal && !p_app_pon_master->vdev_mode)
    {
        _ctc_app_pon_update_uni_default_entry(lchip, 0, 1, p_uni, p_uni_port);
    }

roll_back_2:
    _ctc_app_pon_destroy_mc_gem_port(lchip, p_uni->port);
roll_back_1:
    ctc_pon_destroy_vlan_port(&vlan_port);
roll_back_0:
    ctc_pon_set_port_propery(p_uni->port, &cfg);
    CTC_APP_PON_UNLOCK(lchip);
    return ret;
}

int32
_ctc_app_pon_update_uni_port_vni_tag(ctc_app_pon_db_t* vlan_port_db_tmp, ctc_app_pon_uni_t* p_uni_port)
{
    ctc_pon_vlan_port_t vlan_port ;
    uint8 vdev_id = 0;
    uint16 lport = CTC_MAP_GPORT_TO_LPORT(p_uni_port->port);

    if(vlan_port_db_tmp->p_gem_port_db == NULL)
    {
        return 0;
    }

    if(vlan_port_db_tmp->port != p_uni_port->port)
    {
        return 0;
    }
    vdev_id = p_app_pon_master->p_port_pon[lport].vdev_id;

    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_VN_TAG);
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_UNI);
    vlan_port.gport = vlan_port_db_tmp->port;
    vlan_port.vlan_port_id = vlan_port_db_tmp->vlan_port_id;
    vlan_port.fid = vlan_port_db_tmp->fid;
    vlan_port.volt_tag_valid = 1;
    vlan_port.volt_tag = p_uni_port->vn_tag?p_app_pon_master->vdev_base_vlan + p_app_pon_master->vdev_num:(p_app_pon_master->vdev_base_vlan+vdev_id);
    vlan_port.logic_dest_port = p_app_pon_master->nni_logic_port[vdev_id];
    vlan_port.vn_tag = p_uni_port->vn_tag;
    ctc_pon_update_vlan_port(&vlan_port);

    return CTC_E_NONE;

}


int32
ctc_app_pon_update_uni(uint8 lchip, ctc_app_pon_uni_t* p_uni)
{
    ctc_app_pon_uni_db_t* p_uni_port = NULL;

    /* CHECK */
    CTC_PTR_VALID_CHECK(p_uni);
    CTC_APP_PON_INIT_CHECK();
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_UNI_PORT, p_uni->port, 0));
    if(CTC_APP_PON_UNI_PORT_VNI_TAG == p_uni->update_type)
    {
        CTC_APP_PON_VLAN_ID_CHECK(p_uni->vn_tag);
    }
    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port",         p_uni->port);

    CTC_APP_PON_LOCK(lchip);
    CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_get_uni_port(lchip, p_uni->port, &p_uni_port));

    if (0 == p_uni_port->isolated_id)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }
    if(CTC_APP_PON_UNI_PORT_SWAP_PORT == p_uni->update_type)
    {
        if(!p_uni_port->backup_port_valid)
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NOT_READY;
        }
        if(p_uni->swap_port_en == p_uni_port->swap_port_en)
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NONE;
        }
        CTC_ERROR_RETURN_APP_PON_UNLOCK(ctc_port_set_property(p_uni->port, CTC_PORT_PROP_SWAP_CHANNEL, p_uni_port->backup_port));
        p_uni_port->swap_port_en = p_uni->swap_port_en;
    }
    else if(CTC_APP_PON_UNI_PORT_VNI_TAG == p_uni->update_type)
    {
        if(p_uni_port->vn_tag == p_uni->vn_tag)
        {
            CTC_APP_PON_UNLOCK(lchip);
            return CTC_E_NONE;
        }
        ctc_hash_traverse(p_app_pon_master->vlan_port_key_hash,
                          (spool_traversal_fn)_ctc_app_pon_update_uni_port_vni_tag, p_uni);
        p_uni_port->vn_tag = p_uni->vn_tag;
    }

    CTC_APP_PON_UNLOCK(lchip);
    return CTC_E_NONE;


}

int32
ctc_app_pon_destory_uni(uint8 lchip, ctc_app_pon_uni_t* p_uni)
{
    int32 ret = 0;
    uint32 value = 0;
    uint8 is_internal = 0;
    uint32 nh_iloop = 0;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;
    ctc_port_restriction_t isolation;
    ctc_pon_vlan_port_t vlan_port;
    ctc_pon_port_cfg_t cfg;

    /* CHECK */
    CTC_PTR_VALID_CHECK(p_uni);
    CTC_APP_PON_INIT_CHECK();
    CTC_APP_PON_VDEV_ID_CHECK(p_uni->vdev_id);
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_UNI_PORT, p_uni->port, 0));

    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "vDev id",      p_uni->vdev_id);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port",         p_uni->port);

    CTC_APP_PON_LOCK(lchip);
    CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_get_uni_port(lchip, p_uni->port, &p_uni_port));

    if (0 == p_uni_port->isolated_id)
    {
        CTC_APP_DBG_ERROR("The Uni port no exist\n");
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }
    if (0 != p_uni_port->ref_cnt)
    {
        CTC_APP_DBG_ERROR("The Gem port in use, must free all gem ports in the uni port\n");
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_IN_USE;
    }
    ret = ctc_port_get_capability(p_uni->port, CTC_PORT_CAP_TYPE_MAC_ID, &value);
    if(ret < 0)
    {
        ret = 0;
        is_internal = 1;
    }

    /***********************************************/
    /** disable uni port mux gem */
    cfg.value = 0;
    cfg.type = CTC_PON_PORT_CFG_UNI_EN;

    if(!is_internal)
    {
        if(p_uni_port->backup_port_valid)
        {
            value = 0;
            ctc_pon_set_port_propery(p_uni->backup_port, &cfg);
            if(p_uni_port->swap_port_en)
            {
                ctc_port_set_property(p_uni->port, CTC_PORT_PROP_SWAP_CHANNEL, p_uni_port->backup_port);
            }
        }
    }

    /***********************************************/
    /** Port isolateion */
    sal_memset(&isolation, 0, sizeof(isolation));
    isolation.dir = CTC_EGRESS;
    isolation.isolated_id  = 0;
    isolation.mode = CTC_PORT_RESTRICTION_DISABLE;
    isolation.type = CTC_PORT_ISOLATION_ALL;
    ctc_port_set_restriction(p_uni->port, &isolation);

    isolation.dir = CTC_INGRESS;
    ctc_port_set_restriction(p_uni->port, &isolation);

    /***********************************************/
    /** Remove bc/mc nhid from vlan */
    if(p_app_pon_master->mcast_tunnel_vlan != 0xffff && !is_internal && !p_app_pon_master->vdev_mode)
    {
        _ctc_app_pon_update_uni_default_entry(lchip, 0, 1, p_uni, p_uni_port);
    }

    _ctc_app_pon_destroy_mc_gem_port(lchip, p_uni->port);

    /***********************************************/
    /** Disable egress scl pon service do vlan xlate */
    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    vlan_port.gport = p_uni->port;
    vlan_port.flag |= CTC_PON_VLAN_PORT_FLAG_DEFAULT_SERVICE;
    ctc_pon_destroy_vlan_port(&vlan_port);
    value = 0;
    ctc_pon_set_port_propery(p_uni->port, &cfg);

    if(g_app_pon_mode == 1)
    {
        uint32 lpbk_lport = 0;
        ctc_nh_info_t nh_info;
        ctc_internal_port_assign_para_t port_assign;
        ctc_port_scl_property_t scl_prop;

        sal_memset(&nh_info, 0, sizeof(nh_info));
        nh_iloop = p_uni_port->nh_iloop;
        ctc_nh_get_nh_info(nh_iloop, &nh_info);
        if(nh_info.nh_type == CTC_NH_TYPE_ILOOP)
        {
            lpbk_lport = (((nh_info.dsnh_offset[0] >> 16)&0x01)<<7) | (nh_info.dsnh_offset[0]&0x7f);
            ctc_nh_remove_iloop(nh_iloop);

            sal_memset(&scl_prop, 0, sizeof(scl_prop));
            scl_prop.scl_id = 1;
            ctc_port_set_scl_property(port_assign.inter_port, &scl_prop);

            sal_memset(&port_assign, 0, sizeof(port_assign));
            port_assign.inter_port = lpbk_lport;
            port_assign.gchip = lchip;
            port_assign.type = CTC_INTERNAL_PORT_TYPE_ILOOP;
            ctc_free_internal_port(&port_assign);
        }
    }
    sal_memset(p_uni_port, 0, sizeof(ctc_app_pon_uni_db_t));
    CTC_APP_PON_UNLOCK(lchip);

    return ret;
}

int32
ctc_app_pon_get_uni(uint8 lchip, ctc_app_pon_uni_t* p_uni)
{
    int32 ret = 0;
    ctc_app_pon_uni_db_t* p_uni_port = NULL;

    /* CHECK */
    CTC_PTR_VALID_CHECK(p_uni);
    CTC_APP_PON_INIT_CHECK();
    CTC_APP_PON_VDEV_ID_CHECK(p_uni->vdev_id);
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_UNI_PORT, p_uni->port, 0));

    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "vDev id",      p_uni->vdev_id);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port",         p_uni->port);

    CTC_APP_PON_LOCK(lchip);
    CTC_ERROR_RETURN_APP_PON_UNLOCK(_ctc_app_pon_get_uni_port(lchip, p_uni->port, &p_uni_port));

    if (0 == p_uni_port->isolated_id)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }

    p_uni->vdev_id = p_uni_port->vdev_id;
    p_uni->mc_nhid = p_uni_port->mc_xlate_nhid;
    p_uni->backup_port_valid = p_uni_port->backup_port_valid;
    p_uni->backup_port = p_uni_port->backup_port;
    CTC_APP_PON_UNLOCK(lchip);

    return ret;
}

#define _____NNI_PORT_____ ""

int32
ctc_app_pon_create_nni(uint8 lchip, ctc_app_pon_nni_t* p_nni)
{
    int32 ret = 0;
    uint16 max_num = 0;
    uint8 linkagg_id = 0;
    uint16 mem_count = 0;
    uint8 mem_index = 0;
    uint32 logic_port = 0;
    uint32 nh_id = 0;
    uint32* p_gports = NULL;
    uint32 temp_gport = 0;
    uint32 mcast_nh_id = 0;
    uint32 mcast_group_nh_id = 0;
    uint32 mcast_group_id = 0;
    uint8 new_logic_port = 0;
    ctc_opf_t opf;
    ctc_app_pon_nni_port_db_t nni_port_db;
    ctc_app_pon_nni_port_db_t* p_nni_port_db = NULL;
    ctc_mcast_nh_param_group_t mcast_group;
    ctc_pon_vlan_port_t vlan_port;
    ctc_pon_port_cfg_t cfg;
    ctc_l2dflt_addr_t l2dflt;
    ctc_vlan_edit_nh_param_t nni_xlate_nh;

    /* CHECK */
    CTC_APP_PON_INIT_CHECK();
    CTC_PTR_VALID_CHECK(p_nni);
    CTC_APP_PON_VDEV_ID_CHECK(p_nni->vdev_id);

    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "vDev id", p_nni->vdev_id);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port", p_nni->port);

    CTC_APP_PON_LOCK(lchip);
    /* Check the nni exitst*/
    sal_memset(&nni_port_db, 0, sizeof(nni_port_db));
    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    nni_port_db.port = p_nni->port;
    p_nni_port_db = ctc_hash_lookup(p_app_pon_master->nni_port_hash, &nni_port_db);
    if (NULL != p_nni_port_db)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_EXIST;
    }

    MALLOC_POINTER(ctc_app_pon_nni_port_db_t, p_nni_port_db);
    if (NULL == p_nni_port_db)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NO_MEMORY;
    }

    ctc_linkagg_get_max_mem_num(&max_num);
    p_gports = (uint32*)mem_malloc(MEM_SYSTEM_MODULE, sizeof(uint32)*max_num);
    if (NULL == p_gports)
    {
        ret = CTC_E_NO_MEMORY;
        goto roll_back_0;
    }

    sal_memset(p_gports, 0, sizeof(uint32)*max_num);
    if (CTC_IS_LINKAGG_PORT(p_nni->port))
    {
        linkagg_id = CTC_GPORT_LINKAGG_ID(p_nni->port);
        ctc_linkagg_get_member_ports(linkagg_id, p_gports, &mem_count);
    }
    else
    {
        mem_count = 1;
        *p_gports = p_nni->port;
    }

    if (0 == p_app_pon_master->nni_port_cnt[p_nni->vdev_id])
    {
        /* OPF */
        sal_memset(&opf, 0, sizeof(opf));
        opf.pool_type = CTC_OPF_VLAN_PORT;
        opf.pool_index= CTC_APP_PON_OPF_LOGIC_PORT;
        CTC_ERROR_GOTO(ctc_opf_alloc_offset(&opf, 1, &logic_port), ret, roll_back_0);
        CTC_APP_DBG_INFO("OPF nni logic port: %u\n", logic_port);
        new_logic_port = 1;
        CTC_ERROR_GOTO(_ctc_app_pon_alloc_nhid(lchip, &mcast_nh_id), ret, roll_back_1);
        sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
        mcast_group.mc_grp_id = ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[p_nni->vdev_id], 2);
        CTC_ERROR_GOTO(ctc_nh_add_mcast(mcast_nh_id, &mcast_group), ret, roll_back_2);
    }
    else
    {
        logic_port = p_app_pon_master->nni_logic_port[p_nni->vdev_id];
        mcast_nh_id = p_app_pon_master->nni_mcast_nhid[p_nni->vdev_id];
    }

    /* linkagg nni port property should set by user */
    vlan_port.flag |= CTC_PON_VLAN_PORT_FLAG_DEFAULT_SERVICE;
    vlan_port.flag |= CTC_PON_VLAN_PORT_FLAG_FROM_NNI;
    vlan_port.fid = p_app_pon_master->default_bcast_fid[p_nni->vdev_id];
    vlan_port.volt_tag_valid = 1;
    vlan_port.volt_tag = p_app_pon_master->vdev_base_vlan + p_nni->vdev_id;


    cfg.criteria = p_app_pon_master->fid_mode?CTC_PON_VLAN_PORT_MATCH_SVLAN:CTC_PON_VLAN_PORT_MATCH_SVLAN_CVLAN;
    if(p_app_pon_master->mcast_tunnel_vlan != 0xffff)
    {
        CTC_SET_FLAG(cfg.flag, CTC_PON_PORT_FLAG_DIS_UNKNOWN_MCAST_LOOKUP);
    }
    for (mem_index=0; mem_index<mem_count; mem_index++)
    {
        temp_gport = p_gports[mem_index];
        cfg.value = 1;
        cfg.type = CTC_PON_PORT_CFG_NNI_EN;
        CTC_ERROR_GOTO(ctc_pon_set_port_propery(temp_gport, &cfg), ret, roll_back_3);
        vlan_port.gport = temp_gport;
        CTC_ERROR_GOTO(ctc_pon_create_vlan_port(&vlan_port), ret, roll_back_3);
        cfg.value = logic_port;
        cfg.type = CTC_PON_PORT_CFG_NNI_LOGIC_PORT;
        CTC_ERROR_GOTO(ctc_pon_set_port_propery(temp_gport, &cfg), ret, roll_back_3);

        if (!p_nni->rx_en)
        {
            CTC_ERROR_GOTO(ctc_port_set_receive_en(temp_gport, FALSE), ret, roll_back_3);
        }
    }

    p_nni->logic_port = logic_port;

    /* Add nni member to nni mcast group */
    CTC_ERROR_GOTO(ctc_nh_get_l2uc(p_nni->port, CTC_NH_PARAM_BRGUC_SUB_TYPE_BASIC, &nh_id), ret, roll_back_4);
    mcast_group_id = ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[p_nni->vdev_id], 2);
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.mc_grp_id = mcast_group_id;
    mcast_group.opcode = CTC_NH_PARAM_MCAST_ADD_MEMBER;
    mcast_group.mem_info.ref_nhid = nh_id;
    mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
    CTC_ERROR_GOTO(ctc_nh_update_mcast(mcast_nh_id, &mcast_group), ret, roll_back_4);

    /*Add nni member*/
    mcast_group_id = ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[p_nni->vdev_id], 4);
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.mc_grp_id = mcast_group_id;
    mcast_group.opcode = CTC_NH_PARAM_MCAST_ADD_MEMBER;
    mcast_group.mem_info.ref_nhid = nh_id;
    mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
    mcast_group_nh_id = p_app_pon_master->default_unknown_bcast_nhid[p_nni->vdev_id];
    CTC_ERROR_GOTO(ctc_nh_update_mcast(mcast_group_nh_id, &mcast_group), ret, roll_back_5);
    mcast_group_nh_id = p_app_pon_master->glb_unknown_bcast_nhid;
    ctc_nh_update_mcast(mcast_group_nh_id, &mcast_group);

    if(p_app_pon_master->vdev_mode)
    {
        CTC_ERROR_GOTO(_ctc_app_pon_alloc_nhid(lchip, &p_nni_port_db->mc_xlate_nhid), ret, roll_back_5);

        sal_memset(&nni_xlate_nh, 0, sizeof(nni_xlate_nh));
        nni_xlate_nh.gport_or_aps_bridge_id = p_nni->port;
        nni_xlate_nh.vlan_edit_info.svlan_edit_type = CTC_VLAN_EGRESS_EDIT_INSERT_VLAN;
        nni_xlate_nh.vlan_edit_info.cvlan_edit_type = CTC_VLAN_EGRESS_EDIT_KEEP_VLAN_UNCHANGE;
        nni_xlate_nh.vlan_edit_info.output_svid = p_app_pon_master->vdev_base_vlan + p_nni->vdev_id;
        CTC_SET_FLAG(nni_xlate_nh.vlan_edit_info.edit_flag, CTC_VLAN_EGRESS_EDIT_OUPUT_SVID_VALID);
        CTC_SET_FLAG(nni_xlate_nh.vlan_edit_info.flag, CTC_VLAN_NH_LENGTH_ADJUST_EN);
        CTC_APP_DBG_INFO("nh-mc xlate nhid: %u\n", p_nni_port_db->mc_xlate_nhid);
        CTC_ERROR_GOTO(ctc_nh_add_xlate(p_nni_port_db->mc_xlate_nhid, &nni_xlate_nh), ret, roll_back_6);

        sal_memset(&l2dflt, 0, sizeof(l2dflt));
        l2dflt.fid = p_app_pon_master->glb_default_bcast_fid;
        l2dflt.l2mc_grp_id = p_app_pon_master->glb_default_bcast_fid;
        l2dflt.with_nh = 1;
        l2dflt.member.nh_id = p_nni_port_db->mc_xlate_nhid;
        CTC_ERROR_GOTO(ctc_l2_add_port_to_default_entry(&l2dflt), ret, roll_back_7);
    }
    p_app_pon_master->nni_logic_port[p_nni->vdev_id] = logic_port;
    p_app_pon_master->nni_mcast_nhid[p_nni->vdev_id] = mcast_nh_id;

    ctc_l2_set_nhid_by_logic_port(logic_port, nh_id);

    p_nni_port_db->port = p_nni->port;
    p_nni_port_db->vdev_id = p_nni->vdev_id;
    p_nni_port_db->nni_logic_port = logic_port;
    p_nni_port_db->nni_nh_id = nh_id;
    p_nni_port_db->rx_en = p_nni->rx_en;
    ctc_hash_insert(p_app_pon_master->nni_port_hash, (void*)p_nni_port_db);

    p_app_pon_master->nni_port_cnt[p_nni->vdev_id]++;
    if(p_app_pon_master->nni_port_cnt[p_nni->vdev_id] == 1)
    {
        p_app_pon_master->nni_port[p_nni->vdev_id] = p_gports[0];
    }
    CTC_APP_PON_UNLOCK(lchip);

    mem_free(p_gports);

    return CTC_E_NONE;
roll_back_7:
    ctc_nh_remove_xlate(p_nni_port_db->mc_xlate_nhid);
roll_back_6:
    _ctc_app_pon_free_nhid(lchip, p_nni_port_db->mc_xlate_nhid);
roll_back_5:
    mcast_group_id = ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[p_nni->vdev_id], 2);
    mcast_group.mc_grp_id = mcast_group_id;
    mcast_group.opcode = CTC_NH_PARAM_MCAST_DEL_MEMBER;
    mcast_group.mem_info.ref_nhid = nh_id;
    mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
    ctc_nh_update_mcast(mcast_nh_id, &mcast_group);

roll_back_4:
    for (mem_index=0; mem_index<mem_count; mem_index++)
    {
        temp_gport = p_gports[mem_index];
        cfg.value = 0;
        ctc_pon_set_port_propery(temp_gport, &cfg);
        vlan_port.gport = temp_gport;
        ctc_pon_destroy_vlan_port(&vlan_port);
        ctc_pon_set_port_propery(temp_gport, &cfg);

        if (!p_nni->rx_en)
        {
            ctc_port_set_receive_en(temp_gport, TRUE);
        }
    }

roll_back_3:
    if (0 == p_app_pon_master->nni_port_cnt[p_nni->vdev_id])
    {
        ctc_nh_remove_mcast(mcast_nh_id);
    }
roll_back_2:
    if (0 == p_app_pon_master->nni_port_cnt[p_nni->vdev_id])
    {
        _ctc_app_pon_free_nhid(lchip, mcast_nh_id);
    }
roll_back_1:
    if (new_logic_port)
    {
        ctc_opf_free_offset(&opf, 1, logic_port);
    }
roll_back_0:
    if (p_gports)
    {
        mem_free(p_gports);
    }
    if (p_nni_port_db)
    {
        mem_free(p_nni_port_db);
    }

    CTC_APP_PON_UNLOCK(lchip);

    return ret;
}

int32
ctc_app_pon_destory_nni(uint8 lchip, ctc_app_pon_nni_t* p_nni)
{
    int32 ret = CTC_E_NONE;
    uint16 max_num = 0;
    uint8 linkagg_id = 0;
    uint16 mem_count = 0;
    uint8 mem_index = 0;
    uint32 nh_id = 0;
    uint32 mcast_group_id = 0;
    uint32 mcast_group_nh_id = 0;
    uint32* p_gports = NULL;
    uint32 temp_gport = 0;
    ctc_opf_t opf;
    ctc_app_pon_nni_port_db_t nni_port_db;
    ctc_app_pon_nni_port_db_t* p_nni_port_db = NULL;
    ctc_mcast_nh_param_group_t mcast_group;
    ctc_pon_vlan_port_t vlan_port;
    ctc_pon_port_cfg_t cfg;
    ctc_l2dflt_addr_t l2dflt;

    /* CHECK */
    CTC_APP_PON_INIT_CHECK();
    CTC_PTR_VALID_CHECK(p_nni);
    CTC_APP_PON_VDEV_ID_CHECK(p_nni->vdev_id);
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_NNI_PORT, p_nni->port, 0));

    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "vDev id", p_nni->vdev_id);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port", p_nni->port);

    CTC_APP_PON_LOCK(lchip);
    /* Check the nni not exitst*/
    sal_memset(&nni_port_db, 0, sizeof(nni_port_db));
    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    nni_port_db.port = p_nni->port;
    p_nni_port_db = ctc_hash_lookup(p_app_pon_master->nni_port_hash, &nni_port_db);
    if (NULL == p_nni_port_db)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }

    CTC_APP_DBG_INFO("NNI logic port: %u\n", p_nni_port_db->nni_logic_port);

    CTC_ERROR_GOTO(ctc_nh_get_l2uc(p_nni->port, CTC_NH_PARAM_BRGUC_SUB_TYPE_BASIC, &nh_id), ret, roll_back_0);

    if(p_app_pon_master->vdev_mode)
    {
        sal_memset(&l2dflt, 0, sizeof(l2dflt));
        l2dflt.fid = p_app_pon_master->glb_default_bcast_fid;
        l2dflt.l2mc_grp_id = p_app_pon_master->glb_default_bcast_fid;
        l2dflt.with_nh = 1;
        l2dflt.member.nh_id = p_nni_port_db->mc_xlate_nhid;
        ctc_l2_remove_port_from_default_entry(&l2dflt);
        ctc_nh_remove_xlate(p_nni_port_db->mc_xlate_nhid);
         _ctc_app_pon_free_nhid(lchip, p_nni_port_db->mc_xlate_nhid);

    }

    /*Add nni member*/
    mcast_group_id = ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[p_nni->vdev_id], 4);
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.mc_grp_id = mcast_group_id;
    mcast_group.opcode = CTC_NH_PARAM_MCAST_DEL_MEMBER;
    mcast_group.mem_info.ref_nhid = nh_id;
    mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
    mcast_group_nh_id = p_app_pon_master->default_unknown_bcast_nhid[p_nni->vdev_id];
    ctc_nh_update_mcast(mcast_group_nh_id, &mcast_group);
    mcast_group_nh_id = p_app_pon_master->glb_unknown_bcast_nhid;
    ctc_nh_update_mcast(mcast_group_nh_id, &mcast_group);

    mcast_group_id = ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[p_nni->vdev_id], 2);
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.mc_grp_id = mcast_group_id;
    mcast_group.opcode = CTC_NH_PARAM_MCAST_DEL_MEMBER;
    mcast_group.mem_info.ref_nhid = nh_id;
    mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
    ctc_nh_update_mcast(p_app_pon_master->nni_mcast_nhid[p_nni_port_db->vdev_id], &mcast_group);

    ctc_linkagg_get_max_mem_num(&max_num);
    p_gports = (uint32*)mem_malloc(MEM_SYSTEM_MODULE, sizeof(uint32)*max_num);
    if (NULL == p_gports)
    {
        ret = CTC_E_NO_MEMORY;
        goto roll_back_0;
    }

    sal_memset(p_gports, 0, sizeof(uint32)*max_num);
    if (CTC_IS_LINKAGG_PORT(p_nni->port))
    {
        linkagg_id = CTC_GPORT_LINKAGG_ID(p_nni->port);
        ctc_linkagg_get_member_ports(linkagg_id, p_gports, &mem_count);
    }
    else
    {
        mem_count = 1;
        *p_gports = p_nni->port;
    }
    vlan_port.flag |= CTC_PON_VLAN_PORT_FLAG_DEFAULT_SERVICE;
    cfg.value = 0;
    for (mem_index=0; mem_index<mem_count; mem_index++)
    {
        temp_gport = p_gports[mem_index];
        vlan_port.gport = temp_gport;
        ctc_pon_destroy_vlan_port(&vlan_port);
        cfg.type = CTC_PON_PORT_CFG_NNI_EN;
        ctc_pon_set_port_propery(temp_gport, &cfg);
        cfg.type = CTC_PON_PORT_CFG_NNI_LOGIC_PORT;
        ctc_pon_set_port_propery(temp_gport, &cfg);

        if (!p_nni->rx_en)
        {
            ctc_port_set_receive_en(temp_gport, TRUE);
        }
    }
    ctc_l2_set_nhid_by_logic_port(p_nni_port_db->nni_logic_port, 0);
    p_app_pon_master->nni_port_cnt[p_nni_port_db->vdev_id]--;
    if (0 == p_app_pon_master->nni_port_cnt[p_nni_port_db->vdev_id])
    {
        /* Free opf offset */
        sal_memset(&opf, 0, sizeof(opf));
        opf.pool_type = CTC_OPF_VLAN_PORT;
        opf.pool_index= CTC_APP_PON_OPF_LOGIC_PORT;
        ctc_opf_free_offset(&opf, 1, p_nni_port_db->nni_logic_port);
        p_app_pon_master->nni_logic_port[p_nni_port_db->vdev_id] = 0;

        ctc_nh_remove_mcast(p_app_pon_master->nni_mcast_nhid[p_nni_port_db->vdev_id]);
        _ctc_app_pon_free_nhid(lchip, p_app_pon_master->nni_mcast_nhid[p_nni_port_db->vdev_id]);
        p_app_pon_master->nni_mcast_nhid[p_nni_port_db->vdev_id] = 0;
    }

    /*remove nni port db from hash*/
    ctc_hash_remove(p_app_pon_master->nni_port_hash, (void*)p_nni_port_db);
    mem_free(p_nni_port_db);
roll_back_0:
    if(p_gports)
    {
        mem_free(p_gports);
    }
    CTC_APP_PON_UNLOCK(lchip);

    return ret;
}

int32
ctc_app_pon_update_nni(uint8 lchip, ctc_app_pon_nni_t* p_nni)
{
    int32 ret = CTC_E_NONE;
    uint16 max_num = 0;
    uint8 linkagg_id = 0;
    uint16 mem_count = 0;
    uint8 mem_index = 0;
    uint32 value = 0;
    uint32* p_gports = NULL;
    uint32 temp_gport = 0;
    ctc_app_pon_nni_port_db_t nni_port_db;
    ctc_app_pon_nni_port_db_t* p_nni_port_db = NULL;

    /* CHECK */
    CTC_APP_PON_INIT_CHECK();
    CTC_PTR_VALID_CHECK(p_nni);
    CTC_APP_PON_VDEV_ID_CHECK(p_nni->vdev_id);
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_NNI_PORT, p_nni->port, 0));

    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "vDev id", p_nni->vdev_id);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port", p_nni->port);

    CTC_APP_PON_LOCK(lchip);

    /* Check the nni not exitst*/
    sal_memset(&nni_port_db, 0, sizeof(nni_port_db));
    nni_port_db.port = p_nni->port;
    p_nni_port_db = ctc_hash_lookup(p_app_pon_master->nni_port_hash, &nni_port_db);
    if (NULL == p_nni_port_db)
    {
        ret =  CTC_E_NOT_EXIST;
        goto roll_back_0;
    }

    ctc_linkagg_get_max_mem_num(&max_num);
    p_gports = (uint32*)mem_malloc(MEM_SYSTEM_MODULE, sizeof(uint32)*max_num);
    if (NULL == p_gports)
    {
        ret = CTC_E_NO_MEMORY;
        goto roll_back_0;
    }

    sal_memset(p_gports, 0, sizeof(uint32)*max_num);
    if (CTC_IS_LINKAGG_PORT(p_nni->port))
    {
        linkagg_id = CTC_GPORT_LINKAGG_ID(p_nni->port);
        ctc_linkagg_get_member_ports(linkagg_id, p_gports, &mem_count);
    }
    else
    {
        mem_count = 1;
        *p_gports = p_nni->port;
    }

    if(p_nni->rx_en != p_nni_port_db->rx_en)
    {
        value = p_nni->rx_en?1:0;
        for (mem_index=0; mem_index<mem_count; mem_index++)
        {
            temp_gport = p_gports[mem_index];
            ctc_port_set_receive_en(temp_gport, value);
        }
        p_nni_port_db->rx_en = p_nni->rx_en;
    }

    mem_free(p_gports);

roll_back_0:
    CTC_APP_PON_UNLOCK(lchip);

    return ret;
}

int32
ctc_app_pon_get_nni(uint8 lchip, ctc_app_pon_nni_t* p_nni)
{
    uint32 logic_port = 0;
    ctc_app_pon_nni_port_db_t nni_port_db;
    ctc_app_pon_nni_port_db_t* p_nni_port_db = NULL;

    /* CHECK */
    CTC_APP_PON_INIT_CHECK();
    CTC_PTR_VALID_CHECK(p_nni);
    CTC_APP_PON_VDEV_ID_CHECK(p_nni->vdev_id);
    CTC_ERROR_RETURN(_ctc_app_pon_check(lchip, CTC_APP_PON_TYPE_NNI_PORT, p_nni->port, 0));

    /* Debug */
    CTC_APP_DBG_FUNC();
    CTC_APP_DBG_PARAM("-------------------------------------------------\n");
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "vDev id", p_nni->vdev_id);
    CTC_APP_DBG_PARAM("%-40s :%10u\n", "port", p_nni->port);

    CTC_APP_PON_LOCK(lchip);

    /* Check the nni not exitst*/
    sal_memset(&nni_port_db, 0, sizeof(nni_port_db));
    nni_port_db.port = p_nni->port;
    p_nni_port_db = ctc_hash_lookup(p_app_pon_master->nni_port_hash, &nni_port_db);
    if (NULL == p_nni_port_db)
    {
        CTC_APP_PON_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }

    logic_port = p_nni_port_db->nni_logic_port;

    CTC_APP_PON_UNLOCK(lchip);

    if (0 == logic_port)
    {
        return CTC_E_NOT_EXIST;
    }

    p_nni->logic_port = logic_port;

    return CTC_E_NONE;
}



#define _______LEARN_AGING________
STATIC int32
_ctc_app_pon_sync_gem_port_mac_limit(uint8 lchip, ctc_app_pon_gem_port_db_t* p_gem_port_find, uint8 enable, uint8* need_add)
{
    ctc_app_pon_bpe_gem_port_t bpe_gem_port;
    ctc_pon_gem_port_t gem_port;

    if (p_gem_port_find)
    {
        sal_memset(&gem_port, 0, sizeof(gem_port));
        gem_port.gport = p_gem_port_find->port;
        gem_port.tunnel_value = p_gem_port_find->tunnel_value;
        CTC_ERROR_RETURN(ctc_pon_get_gem_port(&gem_port));

        *need_add = TRUE;
        sal_memset(&bpe_gem_port, 0, sizeof(ctc_app_pon_bpe_gem_port_t));
        bpe_gem_port.lport = CTC_MAP_GPORT_TO_LPORT(p_gem_port_find->port);
        bpe_gem_port.gem_vlan = p_gem_port_find->tunnel_value;
        bpe_gem_port.logic_port = p_gem_port_find->logic_port;
        bpe_gem_port.pass_through_en = p_gem_port_find->pass_trough_en;
        if (enable && (p_gem_port_find->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE) && (p_gem_port_find->limit_count == p_gem_port_find->limit_num))
        {
            *need_add = FALSE;
        }
        else if ((!enable) && (p_gem_port_find->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE) && (p_gem_port_find->limit_count == p_gem_port_find->limit_num))
        {
            gem_port.limit_action = CTC_MACLIMIT_ACTION_NONE;
            CTC_SET_FLAG(gem_port.flag, CTC_PON_GEM_PORT_FLAG_MAC_LIMIT);
            //CTC_APP_PON_API_CALL(p_app_pon_master->ctc_bpe_add_gem_port, lchip, (void*)&bpe_gem_port);
            ctc_pon_update_gem_port(&gem_port);
            p_gem_port_find->mac_security = CTC_MACLIMIT_ACTION_NONE;
        }

        if (*need_add)
        {
            if (enable)
            {
                p_gem_port_find->limit_count++;
            }
            else
            {
                p_gem_port_find->limit_count--;
            }

            if (enable && (p_gem_port_find->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE) && (p_gem_port_find->limit_count == p_gem_port_find->limit_num)
                && (p_gem_port_find->limit_action == CTC_MACLIMIT_ACTION_DISCARD))
            {
                CTC_SET_FLAG(gem_port.flag, CTC_PON_GEM_PORT_FLAG_MAC_LIMIT);
                gem_port.limit_action = CTC_MACLIMIT_ACTION_DISCARD;
                ctc_pon_update_gem_port(&gem_port);
                //CTC_APP_PON_API_CALL(p_app_pon_master->ctc_bpe_add_gem_port, lchip, (void*)&bpe_gem_port);
                p_gem_port_find->mac_security = CTC_MACLIMIT_ACTION_DISCARD;
            }
            else if (enable && (p_gem_port_find->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE) && (p_gem_port_find->limit_count == p_gem_port_find->limit_num)
                && (p_gem_port_find->limit_action == CTC_MACLIMIT_ACTION_TOCPU))
            {
                CTC_SET_FLAG(gem_port.flag, CTC_PON_GEM_PORT_FLAG_MAC_LIMIT);
                gem_port.limit_action = CTC_MACLIMIT_ACTION_TOCPU;
                ctc_pon_update_gem_port(&gem_port);
                //CTC_APP_PON_API_CALL(p_app_pon_master->ctc_bpe_add_gem_port, lchip, (void*)&bpe_gem_port);
                p_gem_port_find->mac_security = CTC_MACLIMIT_ACTION_TOCPU;
            }
        }
    }

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_set_fid_mac_limit_action(void* node, void* user_data)
{
    uint8 limit_action = 0;
    uint8 vdev_id = 0;
    uint16 data = 0;
    ctc_app_pon_fid_db_t* p_port_fid_db = (ctc_app_pon_fid_db_t*)(((ctc_spool_node_t*)node)->data);

    data = *(uint16*)user_data;

    limit_action = data & 0xFF;
    vdev_id = (data>>8)& 0xFF;

    if (p_port_fid_db->vdev_id == vdev_id)
    {
        //CTC_APP_PON_API_CALL(p_app_pon_master->ctc_mac_security_set_fid_learn_limit_action, lchip, p_port_fid_db->fid, limit_action);
        ctc_l2_set_fid_property(p_port_fid_db->fid, CTC_L2_FID_PROP_MAC_LIMIT_ACTION, limit_action);
    }

    return CTC_E_NONE;
}

int32
_ctc_app_pon_traverse_fid(uint8 limit_action, uint8 vdev_id)
{
    uint16 data = 0;

    data = limit_action | (vdev_id<<8);
    CTC_ERROR_RETURN(ctc_spool_traverse(p_app_pon_master->fid_spool,
                          (spool_traversal_fn)_ctc_app_pon_set_fid_mac_limit_action, &data));

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_sync_vdev_mac_limit(uint8 lchip, uint8 vdev_id, uint8 enable, uint8* need_add)
{

    *need_add = TRUE;
    if (enable && (p_app_pon_master->limit_num[vdev_id] != CTC_APP_PON_LIMIT_NUM_DISABLE)
        && (p_app_pon_master->limit_count[vdev_id] == p_app_pon_master->limit_num[vdev_id]))
    {
        *need_add = FALSE;
    }
    else if ((!enable) && (p_app_pon_master->limit_num[vdev_id] != CTC_APP_PON_LIMIT_NUM_DISABLE)
        && (p_app_pon_master->limit_count[vdev_id] == p_app_pon_master->limit_num[vdev_id]))
    {
        _ctc_app_pon_traverse_fid(CTC_MACLIMIT_ACTION_NONE, vdev_id);
    }

    if (*need_add)
    {
        if (enable)
        {
            p_app_pon_master->limit_count[vdev_id]++;
        }
        else
        {
            p_app_pon_master->limit_count[vdev_id]--;
        }

        if (enable && (p_app_pon_master->limit_num[vdev_id] != CTC_APP_PON_LIMIT_NUM_DISABLE)
            && (p_app_pon_master->limit_count[vdev_id] == p_app_pon_master->limit_num[vdev_id]))
        {
            _ctc_app_pon_traverse_fid(p_app_pon_master->limit_action[vdev_id], vdev_id);
        }
    }

    return CTC_E_NONE;
}


STATIC int32
_ctc_app_pon_sync_fid_mac_limit(uint8 lchip, uint16 fid, uint8 enable, uint8* need_add)
{
    int32 ret = CTC_E_NONE;
    ctc_app_pon_fid_db_t port_fid_db;
    ctc_app_pon_fid_db_t* p_port_fid_db = NULL;

    sal_memset(&port_fid_db, 0, sizeof(ctc_app_pon_fid_db_t));

    *need_add = TRUE;
    port_fid_db.fid = fid;
    ret = _ctc_app_pon_get_fid_by_fid(&port_fid_db);
    if (!ret)
    {
        return CTC_E_NOT_EXIST;
    }

    p_port_fid_db = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
    if (NULL == p_port_fid_db)
    {
        return CTC_E_NOT_EXIST;
    }

    if (!CTC_IS_BIT_SET(p_app_pon_master->vlan_glb_vdev[p_port_fid_db->pkt_svlan/32], p_port_fid_db->pkt_svlan%32))
    {
        _ctc_app_pon_sync_vdev_mac_limit(lchip, p_port_fid_db->vdev_id, enable, need_add);
    }

    if (enable && (p_port_fid_db->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE)
        && (p_port_fid_db->limit_count == p_port_fid_db->limit_num))
    {
        *need_add = FALSE;
    }
    else if ((!enable) && (p_port_fid_db->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE)
        && (p_port_fid_db->limit_count == (p_port_fid_db->limit_num)))
    {
        ctc_l2_set_fid_property(p_port_fid_db->fid, CTC_L2_FID_PROP_MAC_LIMIT_ACTION, CTC_MACLIMIT_ACTION_NONE);
    }

    if (*need_add)
    {
        if (enable)
        {
            p_port_fid_db->limit_count++;
        }
        else
        {
            p_port_fid_db->limit_count--;
        }

        if (enable && (p_port_fid_db->limit_num != CTC_APP_PON_LIMIT_NUM_DISABLE)
            && (p_port_fid_db->limit_count == p_port_fid_db->limit_num))
        {
            ctc_l2_set_fid_property(p_port_fid_db->fid, CTC_L2_FID_PROP_MAC_LIMIT_ACTION, p_port_fid_db->limit_action);
        }
    }

    return CTC_E_NONE;
}

int32
_ctc_app_pon_add_uplink_svlan_entry(uint8 lchip, uint32 logic_port, uint16 pkt_svlan, uint16 pkt_cvlan, uint16 fid, uint8 vdev_id)
{
    ctc_opf_t opf;
    ctc_pon_vlan_port_t vlan_port;
    uint32 vlan_port_id = 0;
    ctc_field_key_t match_fields[2];
    ctc_app_pon_db_t* p_vlan_port_db = NULL;
    ctc_app_pon_service_t p_vlan_port;
    int32 ret = 0;

    sal_memset(&vlan_port, 0, sizeof(vlan_port));
    MALLOC_POINTER(ctc_app_pon_db_t, p_vlan_port_db);
    if(NULL == p_vlan_port_db)
    {
        return CTC_E_NO_MEMORY;
    }

    sal_memset(&opf, 0, sizeof(opf));
    opf.pool_type = CTC_OPF_VLAN_PORT;
    opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT_ID;
    CTC_ERROR_RETURN(ctc_opf_alloc_offset(&opf, 1, &vlan_port_id));

    sal_memset(p_vlan_port_db, 0, sizeof(ctc_app_pon_db_t));
    sal_memset(&match_fields, 0, sizeof(ctc_field_key_t)*2);
    vlan_port.criteria = CTC_PON_VLAN_PORT_MATCH_SVLAN_CVLAN;
    vlan_port.fields_num = 2;
    match_fields[1].data = pkt_cvlan;
    match_fields[1].type = CTC_FIELD_KEY_CVLAN_ID;
    match_fields[0].data = pkt_svlan;
    match_fields[0].type = CTC_FIELD_KEY_SVLAN_ID;
    vlan_port.match_fields = &match_fields[0];
    vlan_port.fid = fid;
    vlan_port.volt_tag_valid = 1;
    vlan_port.volt_tag = p_app_pon_master->vdev_base_vlan + vdev_id;
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_PON_SERVICE);
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_PASS_THROUGH);
    ctc_app_pon_get_by_logic_port(lchip, logic_port, &p_vlan_port);
    vlan_port.gport = p_vlan_port.port;
    p_vlan_port_db->port = p_vlan_port.port;
    vlan_port.tunnel_value = p_vlan_port.match_tunnel_value;
    p_vlan_port_db->tunnel_value = p_vlan_port.match_tunnel_value;
    vlan_port.vlan_port_id = vlan_port_id;
    CTC_SET_FLAG(vlan_port.flag, CTC_PON_VLAN_PORT_FLAG_FROM_UNI);
    ret = ctc_pon_create_vlan_port(&vlan_port);
    if(ret)
    {
        ctc_opf_free_offset(&opf, 1, vlan_port_id);
        return CTC_E_EXIST;
    }
    p_vlan_port_db->match_svlan = pkt_svlan;
    p_vlan_port_db->match_cvlan = pkt_cvlan;
    p_vlan_port_db->vlan_port_id = vlan_port_id;

    ctc_hash_insert(p_app_pon_master->vlan_port_key_hash, p_vlan_port_db);

    return CTC_E_NONE;

}

STATIC int32
_ctc_app_pon_add_fdb_learn_with_def_fid(uint8 lchip, uint16 vdev_id, uint16 pkt_svlan, uint16 pkt_cvlan, uint16 logic_port, uint16* p_fid)
{
    ctc_app_pon_fid_db_t port_fid_db;
    ctc_app_pon_fid_db_t* p_port_fid_db = NULL;
    uint8 alloc_fid = 0;


    sal_memset(&port_fid_db, 0, sizeof(ctc_app_pon_fid_db_t));
    port_fid_db.vdev_id = vdev_id;
    port_fid_db.pkt_svlan = pkt_svlan;
    port_fid_db.pkt_cvlan = p_app_pon_master->fid_mode?0:pkt_cvlan;
    port_fid_db.is_pass_through = 1;


    p_port_fid_db = ctc_spool_lookup(p_app_pon_master->fid_spool, &port_fid_db);
    if(NULL == p_port_fid_db)
    {
        alloc_fid = 1;
        CTC_ERROR_RETURN(ctc_spool_add(p_app_pon_master->fid_spool, &port_fid_db, NULL, &p_port_fid_db));
        p_port_fid_db->is_pass_through = 1;
    }

    if (logic_port != p_app_pon_master->nni_logic_port[vdev_id])
    {
        _ctc_app_pon_add_uplink_svlan_entry(lchip, logic_port, pkt_svlan, pkt_cvlan, p_port_fid_db->fid, vdev_id);
    }

    *p_fid = p_port_fid_db->fid;

    if(!alloc_fid)
    {
        return CTC_E_NONE;
    }

    _ctc_app_pon_create_downlink_service(lchip, NULL, p_port_fid_db);

    return CTC_E_NONE;
}

int32
_ctc_app_pon_hw_learning_sync(uint8 gchip, void* p_data)
{
    uint8 lchip = 0;
    uint8 need_fid_add = 0;
    uint8 need_gem_port_add = 0;
    uint16 pkt_svlan = 0;
    uint16 pkt_cvlan = 0;
    uint32 index = 0;
    int32 ret = CTC_E_NONE;
    uint32 nhid = 0;
    ctc_learning_cache_t* p_cache = (ctc_learning_cache_t*)p_data;
    ctc_l2_addr_t l2_addr;
    ctc_app_pon_gem_port_db_t* p_gem_port_find = NULL;
    ctc_app_pon_db_t* p_vlan_port_db = NULL;
    ctc_app_pon_nni_port_db_t* p_nni_port_find = NULL;
    uint16 fid_new = 0;

    sal_memset(&l2_addr, 0, sizeof(l2_addr));

    ctc_app_index_get_lchip_id(gchip, &lchip);
    for (index = 0; index < p_cache->entry_num; index++)
    {
        /* pizzabox */
        l2_addr.fid = p_cache->learning_entry[index].fid;
        l2_addr.flag = 0;

        l2_addr.mac[0] = (p_cache->learning_entry[index].mac_sa_32to47 & 0xff00) >> 8;
        l2_addr.mac[1] = (p_cache->learning_entry[index].mac_sa_32to47 & 0xff);
        l2_addr.mac[2] = (p_cache->learning_entry[index].mac_sa_0to31 & 0xff000000) >> 24;
        l2_addr.mac[3] = (p_cache->learning_entry[index].mac_sa_0to31 & 0xff0000) >> 16;
        l2_addr.mac[4] = (p_cache->learning_entry[index].mac_sa_0to31 & 0xff00) >> 8;
        l2_addr.mac[5] = (p_cache->learning_entry[index].mac_sa_0to31 & 0xff);

        if (p_cache->learning_entry[index].is_logic_port)
        {

            l2_addr.gport = p_cache->learning_entry[index].logic_port;
            pkt_svlan = p_cache->learning_entry[index].svlan_id;
            pkt_cvlan = p_cache->learning_entry[index].cvlan_id;

            CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Add fdb, logic_port:%u, svlan:%u, cvlan:%u \n",
                            l2_addr.gport,
                            pkt_svlan,
                            pkt_cvlan);

            /*ONU*/
            p_vlan_port_db = _ctc_app_pon_find_vlan_port_db(lchip, l2_addr.gport);
            if ((NULL != p_vlan_port_db) && (((pkt_svlan == p_vlan_port_db->match_svlan)
                && (pkt_cvlan == p_vlan_port_db->match_cvlan))
                || ((p_vlan_port_db->match_svlan_end != 0)        /*ONU Vlan Range*/
                && ( pkt_svlan >= p_vlan_port_db->match_svlan)
                && (pkt_svlan <= p_vlan_port_db->match_svlan_end))
                || ((p_vlan_port_db->criteria == CTC_APP_PON_MATCH_PORT_TUNNEL_FLEX)
                && (p_vlan_port_db->fid == l2_addr.fid))))
            {
                if (l2_addr.fid != p_app_pon_master->default_bcast_fid[p_vlan_port_db->vdev_id])
                {
                    nhid =  p_vlan_port_db->xlate_nhid;
                    /*mask_valid represent the need set logic_dest_port_valid*/
                    l2_addr.flag |= CTC_L2_FLAG_PON_EN;
                    l2_addr.policer_id = p_vlan_port_db->egress_policer_id;

                    _ctc_app_pon_sync_gem_port_mac_limit(lchip, p_vlan_port_db->p_gem_port_db, TRUE, &need_gem_port_add);

                    _ctc_app_pon_sync_fid_mac_limit(lchip, l2_addr.fid, TRUE, &need_fid_add);
                    if (need_fid_add && need_gem_port_add)
                    {
                        CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Vlan port find nhid:%u!!!\n", nhid);
                        ctc_l2_add_fdb_with_nexthop(&l2_addr, nhid);
                    }
                    else
                    {
                        CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Vlan port mac limit fid %u gem_port %u!!!\n", need_fid_add, need_gem_port_add);
                    }
                    continue;
                }
            }

            /*PON*/
            p_gem_port_find = _ctc_app_pon_find_gem_port_db(lchip, l2_addr.gport);
            if (p_gem_port_find)
            {
                if (l2_addr.fid == p_app_pon_master->default_bcast_fid[p_gem_port_find->vdev_id] || (l2_addr.fid == p_app_pon_master->glb_default_bcast_fid && p_app_pon_master->vdev_mode))
                {
                    _ctc_app_pon_add_fdb_learn_with_def_fid(lchip, p_gem_port_find->vdev_id, pkt_svlan, pkt_cvlan,  l2_addr.gport, &fid_new);
                    ctc_l2_remove_fdb(&l2_addr);
                    l2_addr.fid = fid_new;
                }

                nhid = p_gem_port_find->pon_downlink_nhid;
                l2_addr.flag |= CTC_L2_FLAG_PON_EN;
                l2_addr.cid = 1; /*cid represent pon*/

                _ctc_app_pon_sync_gem_port_mac_limit(lchip, p_gem_port_find, TRUE, &need_gem_port_add);
                _ctc_app_pon_sync_fid_mac_limit(lchip, l2_addr.fid, TRUE, &need_fid_add);
                if (need_fid_add && need_gem_port_add)
                {
                    CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "GemPort find nhid:%d\n", nhid);
                    ctc_l2_add_fdb_with_nexthop(&l2_addr, nhid);
                }
                else
                {
                    CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "GemPort find mac limit fid %u gem_port %u!!!\n", need_fid_add, need_gem_port_add);
                }
                continue;
            }

            /*NNI port*/
            p_nni_port_find = _ctc_app_pon_find_nni_port(lchip, l2_addr.gport);
            if (p_nni_port_find)
            {
                if (l2_addr.fid == p_app_pon_master->default_bcast_fid[p_nni_port_find->vdev_id])
                {
                    _ctc_app_pon_add_fdb_learn_with_def_fid(lchip, p_nni_port_find->vdev_id, pkt_svlan, pkt_cvlan,  l2_addr.gport, &fid_new);
                    ctc_l2_remove_fdb(&l2_addr);
                    l2_addr.fid = fid_new;
                }

                CTC_APP_DBG_INFO("p_app_pon_master->nni_logic_port:%u\n", p_nni_port_find->nni_logic_port);
                nhid = p_app_pon_master->nni_mcast_nhid[p_nni_port_find->vdev_id];
                _ctc_app_pon_sync_fid_mac_limit(lchip, l2_addr.fid, TRUE, &need_fid_add);
                if (need_fid_add)
                {
                    CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "NNI find nhid:%u \n", nhid);
                    ctc_l2_add_fdb_with_nexthop(&l2_addr, nhid);
                }
                else
                {
                    CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "NNI find mac limit fid %u!!!\n", need_fid_add);
                }
                continue;
            }
        }
    }

    return ret;
}

int32
_ctc_app_pon_hw_aging_sync(uint8 gchip, void* p_data)
{
    ctc_aging_fifo_info_t* p_fifo = (ctc_aging_fifo_info_t*)p_data;
    uint8 need_fid_add = 0;
    uint8 need_gem_port_add = 0;
    uint32 i = 0;
    int32 ret = CTC_E_NONE;
    ctc_l2_addr_t l2_addr;
    ctc_l2_addr_t l2_addr_rst;
    uint8 lchip = 0;
    ctc_app_pon_gem_port_db_t* p_gem_port_find = NULL;
    ctc_app_pon_fid_db_t port_fid_db;
    ctc_l2_fdb_query_t fdb_query;
    ctc_l2_fdb_query_rst_t fdb_rst;
    ctc_app_pon_db_t* p_vlan_port_db = NULL;

    sal_memset(&l2_addr_rst, 0, sizeof(ctc_l2_addr_t));

    ctc_app_index_get_lchip_id(gchip, &lchip);
    /*Using Dma*/
    for (i = 0; i < p_fifo->fifo_idx_num; i++)
    {
        ctc_aging_info_entry_t* p_entry = NULL;

        sal_memset(&l2_addr, 0, sizeof(ctc_l2_addr_t));

        p_entry = &(p_fifo->aging_entry[i]);
        l2_addr.fid = p_entry->fid;
        sal_memcpy(l2_addr.mac, p_entry->mac, sizeof(mac_addr_t));

        CTC_SET_FLAG(l2_addr.flag, CTC_L2_FLAG_REMOVE_DYNAMIC);
        sal_memset(&fdb_query, 0, sizeof(ctc_l2_fdb_query_t));
        sal_memset(&fdb_rst, 0, sizeof(ctc_l2_fdb_query_rst_t));
        fdb_query.fid = l2_addr.fid;
        sal_memcpy(fdb_query.mac, p_entry->mac, sizeof(mac_addr_t));
        fdb_query.query_type = CTC_L2_FDB_ENTRY_OP_BY_MAC_VLAN;
        fdb_query.query_flag = CTC_L2_FDB_ENTRY_DYNAMIC;
        fdb_rst.buffer_len = sizeof(ctc_l2_addr_t);
        fdb_rst.buffer = &l2_addr_rst;
        ctc_l2_get_fdb_entry(&fdb_query, &fdb_rst);

        l2_addr.is_logic_port = 1;
        ret = ctc_l2_remove_fdb(&l2_addr);
        l2_addr.gport = fdb_rst.buffer[0].gport;
        p_vlan_port_db = _ctc_app_pon_find_vlan_port_db(lchip, l2_addr.gport);
        if (p_vlan_port_db)
        {
            _ctc_app_pon_sync_gem_port_mac_limit(lchip, p_vlan_port_db->p_gem_port_db, FALSE, &need_gem_port_add);
        }
        else
        {
            p_gem_port_find = _ctc_app_pon_find_gem_port_db(lchip, l2_addr.gport);
            if (p_gem_port_find)
            {
                _ctc_app_pon_sync_gem_port_mac_limit(lchip, p_gem_port_find, FALSE, &need_gem_port_add);
            }
        }
        _ctc_app_pon_sync_fid_mac_limit(lchip, l2_addr.fid, FALSE, &need_fid_add);

        sal_memset(&port_fid_db, 0, sizeof(ctc_app_pon_fid_db_t));
        port_fid_db.fid = l2_addr.fid;
        ret = _ctc_app_pon_get_fid_by_fid(&port_fid_db);
        if (ret && port_fid_db.is_pass_through)
        {
            sal_memset(&fdb_query, 0, sizeof(ctc_l2_fdb_query_t));
            fdb_query.fid = l2_addr.fid;
            fdb_query.gport = l2_addr.gport;
            fdb_query.use_logic_port = 1;
            fdb_query.query_type = CTC_L2_FDB_ENTRY_OP_BY_PORT_VLAN;
            fdb_query.query_flag = CTC_L2_FDB_ENTRY_DYNAMIC;
            ctc_l2_get_fdb_count(&fdb_query);
            CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "fid: %d, logic port: %d \n", fdb_query.fid, fdb_query.gport);

            if ((0 == fdb_query.count)&&(l2_addr.gport != p_app_pon_master->nni_logic_port[port_fid_db.vdev_id]))
            {
                _ctc_app_pon_remove_uplink_svlan_entry(lchip, l2_addr.gport, &port_fid_db);
            }

            sal_memset(&fdb_query, 0, sizeof(ctc_l2_fdb_query_t));
            fdb_query.fid = l2_addr.fid;
            fdb_query.query_type = CTC_L2_FDB_ENTRY_OP_BY_VID;
            fdb_query.query_flag = CTC_L2_FDB_ENTRY_DYNAMIC;
            ctc_l2_get_fdb_count(&fdb_query);
            if(0 == fdb_query.count)
            {
                _ctc_app_pon_remove_fdb_learn_with_def_fid(lchip, &port_fid_db);
            }
        }

        CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Aging Sync: MAC:%.4x.%.4x.%.4x  FID:%-5u\n",
                        sal_ntohs(*(unsigned short*)&l2_addr.mac[0]),
                        sal_ntohs(*(unsigned short*)&l2_addr.mac[2]),
                        sal_ntohs(*(unsigned short*)&l2_addr.mac[4]),
                        l2_addr.fid);

        if (ret)
        {
            CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Aging fdb fail, ret:%u \n", ret);
        }
    }

    return CTC_E_NONE;
}

#define _______INIT________
STATIC int32
_ctc_app_pon_free_db(uint8 lchip)
{
    mem_free(p_app_pon_master->p_port_pon);

    ctc_spool_free(p_app_pon_master->fid_spool);

    ctc_hash_free(p_app_pon_master->vlan_port_key_hash);

    ctc_hash_free(p_app_pon_master->vlan_port_hash);

    ctc_hash_free(p_app_pon_master->gem_port_hash);

    ctc_hash_free(p_app_pon_master->nni_port_hash);

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_init_db(uint8 lchip)
{
    ctc_spool_t spool;
    uint32 capability[CTC_GLOBAL_CAPABILITY_MAX] = {0};
    uint16 fid_num = 0;

    ctc_global_ctl_get(CTC_GLOBAL_CHIP_CAPABILITY, capability);
    CTC_PTR_VALID_CHECK(p_app_pon_master);



    p_app_pon_master->nni_port_hash = ctc_hash_create(1,8,
                                                              (hash_key_fn) _ctc_app_pon_hash_nni_port_make,
                                                              (hash_cmp_fn) _ctc_app_pon_hash_nni_port_cmp);

    p_app_pon_master->gem_port_hash = ctc_hash_create(CTC_APP_PON_SERVICE_HASH_SIZE/CTC_HASH_128_BLOCK_SIZE, CTC_HASH_128_BLOCK_SIZE,
                                                              (hash_key_fn) _ctc_app_pon_hash_gem_port_make,
                                                              (hash_cmp_fn) _ctc_app_pon_hash_gem_port_cmp);

    p_app_pon_master->vlan_port_hash = ctc_hash_create(CTC_APP_PON_SERVICE_HASH_SIZE/CTC_HASH_128_BLOCK_SIZE, CTC_HASH_128_BLOCK_SIZE,
                                                               (hash_key_fn) _ctc_app_pon_hash_make,
                                                               (hash_cmp_fn) _ctc_app_pon_hash_cmp);

    p_app_pon_master->vlan_port_key_hash = ctc_hash_create(CTC_APP_PON_SERVICE_HASH_SIZE/CTC_HASH_128_BLOCK_SIZE, CTC_HASH_128_BLOCK_SIZE,
                                                               (hash_key_fn) _ctc_app_pon_key_hash_make,
                                                               (hash_cmp_fn) _ctc_app_pon_key_hash_cmp);

    if ((NULL == p_app_pon_master->nni_port_hash) || (NULL == p_app_pon_master->gem_port_hash)
        || (NULL == p_app_pon_master->vlan_port_hash) || (NULL == p_app_pon_master->vlan_port_key_hash))
    {
        goto roll_back_0;
    }

    sal_memset(&spool, 0, sizeof(ctc_spool_t));

    fid_num = capability[CTC_GLOBAL_CAPABILITY_MAX_FID]>1024?capability[CTC_GLOBAL_CAPABILITY_MAX_FID]-1024:capability[CTC_GLOBAL_CAPABILITY_MAX_FID];
    spool.lchip = lchip;
    spool.block_num = 1;
    spool.block_size = fid_num;
    spool.max_count = fid_num;
    spool.user_data_size = sizeof(ctc_app_pon_fid_db_t);
    spool.spool_key = (hash_key_fn)_ctc_app_pon_fid_hash_make;
    spool.spool_cmp = (hash_cmp_fn)_ctc_app_pon_fid_hash_cmp;
    spool.spool_alloc = (spool_alloc_fn)_ctc_app_pon_fid_build_index;
    spool.spool_free = (spool_free_fn)_ctc_app_pon_fid_free_index;
    p_app_pon_master->fid_spool = ctc_spool_create(&spool);
    if (NULL == p_app_pon_master->fid_spool)
    {
        goto roll_back_0;
    }

    p_app_pon_master->p_port_pon = (ctc_app_pon_uni_db_t*)mem_malloc(MEM_SYSTEM_MODULE, 512*sizeof(ctc_app_pon_uni_db_t));
    if (NULL == p_app_pon_master->p_port_pon)
    {
        goto roll_back_1;
    }

    sal_memset( p_app_pon_master->p_port_pon, 0, 512*sizeof(ctc_app_pon_uni_db_t));
    /*default all vlan support slice*/
    sal_memset(p_app_pon_master->vlan_glb_vdev, 0, sizeof(uint32)*CTC_APP_PON_VLAN_BITMAP);

    return CTC_E_NONE;

roll_back_1:
    ctc_spool_free(p_app_pon_master->fid_spool);

roll_back_0:
    if (p_app_pon_master->vlan_port_key_hash)
    {
        ctc_hash_free(p_app_pon_master->vlan_port_key_hash);
    }

    if (p_app_pon_master->vlan_port_hash)
    {
        ctc_hash_free(p_app_pon_master->vlan_port_hash);
    }

    if (p_app_pon_master->gem_port_hash)
    {
        ctc_hash_free(p_app_pon_master->gem_port_hash);
    }

    if (p_app_pon_master->nni_port_hash)
    {
        ctc_hash_free(p_app_pon_master->nni_port_hash);
    }


    return CTC_E_NO_MEMORY;
}

STATIC int32
_ctc_app_pon_free_opf(uint8 lchip)
{
    uint8 index = 0;

    for (index=0; index<CTC_APP_PON_OPF_MAX; index++)
    {
        ctc_opf_free(CTC_OPF_VLAN_PORT, index);
    }

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_init_opf(uint8 lchip, uint16 vdev_num)
{
    uint32 capability[CTC_GLOBAL_CAPABILITY_MAX] = {0};
    uint8 def_fid_num = 0;
    ctc_opf_t opf;

    ctc_global_ctl_get(CTC_GLOBAL_CHIP_CAPABILITY, capability);

    ctc_opf_init(CTC_OPF_VLAN_PORT, CTC_APP_PON_OPF_MAX);

    sal_memset(&opf, 0, sizeof(opf));
    opf.pool_type = CTC_OPF_VLAN_PORT;

    opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT;
    ctc_opf_init_offset(&opf, 1, capability[CTC_GLOBAL_CAPABILITY_LOGIC_PORT_NUM]-1);

    opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT_ID;
    ctc_opf_init_offset(&opf, 1, 64*1024);

    def_fid_num = p_app_pon_master->vdev_mode?(vdev_num+2):(vdev_num+1);
    opf.pool_index = CTC_APP_PON_OPF_FID;
    ctc_opf_init_offset(&opf, def_fid_num, capability[CTC_GLOBAL_CAPABILITY_MAX_FID]);

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_free_port(uint8 lchip, uint8 vdev_index)
{
    uint32 nh_id = 0;
    ctc_l2dflt_addr_t l2dflt;

    ctc_scl_destroy_group(CTC_APP_PON_SCL_GROUP_ID+vdev_index);

    ctc_nh_get_mcast_nh(ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[vdev_index], 1), &nh_id);
    ctc_nh_remove_mcast(nh_id);

    _ctc_app_pon_free_nhid(lchip, nh_id);

    ctc_nh_remove_mcast(p_app_pon_master->default_unknown_mcast_nhid[vdev_index]);

    _ctc_app_pon_free_nhid(lchip, p_app_pon_master->default_unknown_mcast_nhid[vdev_index]);

    ctc_nh_remove_mcast(p_app_pon_master->default_unknown_bcast_nhid[vdev_index]);

    _ctc_app_pon_free_nhid(lchip, p_app_pon_master->default_unknown_bcast_nhid[vdev_index]);


    sal_memset(&l2dflt, 0, sizeof(l2dflt));
    l2dflt.fid = p_app_pon_master->default_bcast_fid[vdev_index];
    l2dflt.l2mc_grp_id = ENCODE_MCAST_GROUP_ID(p_app_pon_master->default_mcast_group_id[vdev_index], 0);
    ctc_l2_remove_default_entry(&l2dflt);

    _ctc_app_pon_free_mcast_group_id(lchip, 5, p_app_pon_master->default_mcast_group_id[vdev_index]);

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_free_global_vdev(uint8 lchip, uint32 mcast_id)
{
    ctc_nh_remove_mcast(p_app_pon_master->glb_unknown_mcast_nhid);

    _ctc_app_pon_free_nhid(lchip, p_app_pon_master->glb_unknown_mcast_nhid);

    ctc_nh_remove_mcast(p_app_pon_master->glb_unknown_bcast_nhid);

    _ctc_app_pon_free_nhid(lchip, p_app_pon_master->glb_unknown_bcast_nhid);

    _ctc_app_pon_free_mcast_group_id(lchip, 2, mcast_id);

    return CTC_E_NONE;
}

STATIC int32
_ctc_app_pon_init_global_vdev(uint8 lchip, uint32* p_mcast_id)
{
    uint32 nh_profile_id = 0;
    uint32 mcast_id = 0;
    uint32 glb_mcast_id = 0;
    uint32 logic_port = 0;
    ctc_mcast_nh_param_group_t mcast_group;
    int32 ret = CTC_E_NONE;
    ctc_opf_t opf;
    ctc_l2dflt_addr_t l2dflt;

    CTC_ERROR_RETURN(_ctc_app_pon_alloc_mcast_group_id(lchip, 2, &mcast_id));

    /*alloc unknown ucast profile*/
    CTC_ERROR_GOTO(_ctc_app_pon_alloc_nhid(lchip, &nh_profile_id), ret, roll_back_0);
    p_app_pon_master->glb_unknown_bcast_nhid = nh_profile_id;
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.is_profile = 1;
    mcast_group.mc_grp_id = ENCODE_MCAST_GROUP_ID(mcast_id, 0);
    CTC_ERROR_GOTO(ctc_nh_add_mcast(nh_profile_id, &mcast_group), ret, roll_back_1);

    /*alloc unknown mcast profile*/
    CTC_ERROR_GOTO(_ctc_app_pon_alloc_nhid(lchip, &nh_profile_id), ret, roll_back_2);
    p_app_pon_master->glb_unknown_mcast_nhid = nh_profile_id;
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.is_profile = 1;
    mcast_group.mc_grp_id = ENCODE_MCAST_GROUP_ID(mcast_id, 1);
    CTC_ERROR_GOTO(ctc_nh_add_mcast(nh_profile_id, &mcast_group), ret, roll_back_3);

    *p_mcast_id = mcast_id;

    sal_memset(&opf, 0, sizeof(opf));
    opf.pool_type = CTC_OPF_VLAN_PORT;
    opf.pool_index = CTC_APP_PON_OPF_LOGIC_PORT;
    CTC_ERROR_GOTO(ctc_opf_alloc_offset(&opf, 1, &logic_port), ret, roll_back_4);

    p_app_pon_master->bcast_value_logic_port = logic_port;
    if(p_app_pon_master->vdev_mode)
    {
        p_app_pon_master->glb_default_bcast_fid = CTC_APP_PON_RSV_MCAST_GROUP_ID(p_app_pon_master->vdev_num);
        CTC_ERROR_RETURN(_ctc_app_pon_alloc_mcast_group_id(lchip, 1, &glb_mcast_id));
        sal_memset(&l2dflt, 0, sizeof(l2dflt));
        l2dflt.fid = p_app_pon_master->glb_default_bcast_fid;
        l2dflt.l2mc_grp_id = glb_mcast_id;
        CTC_SET_FLAG(l2dflt.flag, CTC_L2_DFT_VLAN_FLAG_USE_LOGIC_PORT);
        ctc_l2_add_default_entry(&l2dflt);
    }

    return CTC_E_NONE;

roll_back_4:
    ctc_nh_remove_mcast(nh_profile_id);

roll_back_3:
    _ctc_app_pon_free_nhid(lchip, p_app_pon_master->glb_unknown_mcast_nhid);

roll_back_2:
    ctc_nh_remove_mcast(p_app_pon_master->glb_unknown_bcast_nhid);

roll_back_1:
    _ctc_app_pon_free_nhid(lchip, p_app_pon_master->glb_unknown_bcast_nhid);

roll_back_0:
    _ctc_app_pon_free_mcast_group_id(lchip, 2, mcast_id);

    return ret;
}


STATIC int32
_ctc_app_pon_init_port(uint8 lchip, uint8 vdev_index)
{
    uint32 fid = 0;
    uint32 nh_id = 0;
    uint32 nh_profile_id = 0;
    ctc_l2dflt_addr_t l2dflt;
    ctc_mcast_nh_param_group_t mcast_group;
    uint32 mcast_id = 0;
    int32 ret = CTC_E_NONE;

    fid = CTC_APP_PON_RSV_MCAST_GROUP_ID(vdev_index);
    p_app_pon_master->default_bcast_fid[vdev_index] = fid;

    CTC_ERROR_RETURN(_ctc_app_pon_alloc_mcast_group_id(lchip, 5, &mcast_id));
    sal_memset(&l2dflt, 0, sizeof(l2dflt));
    l2dflt.fid = fid;
    l2dflt.l2mc_grp_id = ENCODE_MCAST_GROUP_ID(mcast_id, 0);
    CTC_SET_FLAG(l2dflt.flag, CTC_L2_DFT_VLAN_FLAG_USE_LOGIC_PORT);
    CTC_ERROR_GOTO(ctc_l2_add_default_entry(&l2dflt), ret, roll_back_0);
    /*alloc unknown ucast profile*/
    CTC_ERROR_GOTO(_ctc_app_pon_alloc_nhid(lchip, &nh_profile_id), ret, roll_back_1);
    p_app_pon_master->default_unknown_bcast_nhid[vdev_index] = nh_profile_id;
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.is_profile = 1;
    mcast_group.mc_grp_id = ENCODE_MCAST_GROUP_ID(mcast_id, 4);
    CTC_ERROR_GOTO(ctc_nh_add_mcast(nh_profile_id, &mcast_group), ret, roll_back_2);

    /* add unknown ucast profile to default unknown mcast */
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.mc_grp_id = ENCODE_MCAST_GROUP_ID(mcast_id, 0);
    mcast_group.opcode = CTC_NH_PARAM_MCAST_ADD_MEMBER;
    mcast_group.mem_info.ref_nhid = nh_profile_id;
    mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
    ctc_nh_get_mcast_nh(ENCODE_MCAST_GROUP_ID(mcast_id, 0), &nh_id);
    ctc_nh_update_mcast(nh_id, &mcast_group);

    /*alloc unknown mcast profile*/
    CTC_ERROR_GOTO(_ctc_app_pon_alloc_nhid(lchip, &nh_profile_id), ret, roll_back_3);
    p_app_pon_master->default_unknown_mcast_nhid[vdev_index] = nh_profile_id;
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.is_profile = 1;
    mcast_group.mc_grp_id = ENCODE_MCAST_GROUP_ID(mcast_id, 3);
    CTC_ERROR_GOTO(ctc_nh_add_mcast(nh_profile_id, &mcast_group), ret, roll_back_4);

    /* Alloc default unknown mcast nhid */
    CTC_ERROR_GOTO(_ctc_app_pon_alloc_nhid(lchip, &nh_id), ret, roll_back_5);
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.mc_grp_id = ENCODE_MCAST_GROUP_ID(mcast_id, 1);
    CTC_ERROR_GOTO(ctc_nh_add_mcast(nh_id, &mcast_group), ret, roll_back_6);
    p_app_pon_master->default_mcast_group_id[vdev_index] = mcast_id;
    ctc_l2_set_fid_property(fid, CTC_L2_FID_PROP_BDING_MCAST_GROUP, ENCODE_MCAST_GROUP_ID(mcast_id, 1));

    /* add unknown mcast profile to default unknown mcast */
    sal_memset(&mcast_group, 0, sizeof(ctc_mcast_nh_param_group_t));
    mcast_group.mc_grp_id = ENCODE_MCAST_GROUP_ID(mcast_id, 1);
    mcast_group.opcode = CTC_NH_PARAM_MCAST_ADD_MEMBER;
    mcast_group.mem_info.ref_nhid = nh_profile_id;
    mcast_group.mem_info.member_type = CTC_NH_PARAM_MEM_LOCAL_WITH_NH;
    ctc_nh_update_mcast(nh_id, &mcast_group);

    p_app_pon_master->limit_num[vdev_index] = CTC_APP_PON_LIMIT_NUM_DISABLE;

    return CTC_E_NONE;

roll_back_6:
    _ctc_app_pon_free_nhid(lchip, nh_id);

roll_back_5:
    ctc_nh_remove_mcast(p_app_pon_master->default_unknown_mcast_nhid[vdev_index]);

roll_back_4:
    _ctc_app_pon_free_nhid(lchip, p_app_pon_master->default_unknown_mcast_nhid[vdev_index]);

roll_back_3:
    ctc_nh_remove_mcast(p_app_pon_master->default_unknown_bcast_nhid[vdev_index]);

roll_back_2:
    _ctc_app_pon_free_nhid(lchip, p_app_pon_master->default_unknown_bcast_nhid[vdev_index]);

roll_back_1:
    ctc_l2_remove_default_entry(&l2dflt);

roll_back_0:
    _ctc_app_pon_free_mcast_group_id(lchip, 5, mcast_id);

    return ret;
}

int32 
_ctc_app_pon_init_mode(uint8 lchip)
{
    int32 ret = CTC_E_NONE;
    #if 0
    uint32 cmd = 0;
    uint32 ad_mask[6] = {0};
    uint32 mimicryctl[8];
    uint32 ipe_hdr_rsv;
    #endif
    uint32 field_cnt = 2;
    ctc_acl_hash_field_sel_t acl_field_sel;
    ctc_scl_hash_field_sel_t scl_field_sel;
    ctc_scl_entry_t scl_entry;
    ctc_field_key_t field_key[2];
    
    /*1. create scl1 : ipv4 pkt, do nothing*/
    sal_memset(&scl_field_sel, 0 , sizeof(scl_field_sel));
    scl_field_sel.field_sel_id = CTC_APP_PON_SCL_HASH_FIELD_SEL_ID;
    scl_field_sel.key_type = CTC_SCL_KEY_HASH_L2;
    scl_field_sel.u.l2.eth_type = 1;
    CTC_ERROR_RETURN(ctc_scl_set_hash_field_sel(&scl_field_sel));

    sal_memset(&scl_entry, 0 , sizeof(scl_entry));
    scl_entry.key_type = CTC_SCL_KEY_HASH_L2;
    scl_entry.entry_id = CTC_APP_PON_SCL_FLOW_ENTRY_ID;
    scl_entry.hash_field_sel_id = CTC_APP_PON_SCL_HASH_FIELD_SEL_ID;
    scl_entry.action_type = CTC_SCL_ACTION_FLOW;
    scl_entry.mode = 1;
    CTC_ERROR_RETURN(ctc_scl_add_entry(CTC_SCL_GROUP_ID_HASH_L2, &scl_entry));

    field_key[0].type = CTC_FIELD_KEY_ETHER_TYPE;
    field_key[0].data = 0x0800;
    field_key[1].type = CTC_FIELD_KEY_HASH_VALID;
    field_key[1].data = 1;
    CTC_ERROR_GOTO(ctc_scl_add_key_field_list(scl_entry.entry_id, field_key, &field_cnt), ret, error2);

    CTC_ERROR_GOTO(ctc_scl_install_entry(scl_entry.entry_id), ret, error2);
    
    /*2. cfg rsv register, if not hit scl1 then clear scl0 result*/
    #if 0
    sal_memset(mimicryctl, 0, sizeof(mimicryctl));
    CTC_BMP_SET(ad_mask, 1); /*USERIDHASHTYPE_DOUBLEVLANPORT*/
    CTC_BMP_SET(ad_mask,  0x38+ 64); /*USERIDHASHTYPE_SCLFLOWL2*/
    CTC_BMP_SET(ad_mask, 128);
    CTC_BMP_SET(ad_mask, 129);
    CTC_BMP_SET(ad_mask, 132);
    CTC_BMP_SET(ad_mask, 133);

    SetIpeUserIdMimicryCtl(A, mimicrySclAdMask_f, mimicryctl, ad_mask);
    cmd = DRV_IOW(IpeUserIdMimicryCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, mimicryctl));

    cmd = DRV_IOR(IpeHdrAdjReserved_t, IpeHdrAdjReserved_reserved_f);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ipe_hdr_rsv));
    ipe_hdr_rsv |= (1<<1);
    cmd = DRV_IOW(IpeHdrAdjReserved_t, IpeHdrAdjReserved_reserved_f);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ipe_hdr_rsv));
    #endif
    
    /*3. set acl hash field seltec*/
    sal_memset(&acl_field_sel, 0 , sizeof(acl_field_sel));
    acl_field_sel.field_sel_id = CTC_APP_PON_ACL_HASH_FIELD_SEL_ID;
    acl_field_sel.hash_key_type = CTC_ACL_KEY_HASH_MAC;
    acl_field_sel.u.mac.eth_type = 1;
    acl_field_sel.u.mac.logic_port = 1;
    CTC_ERROR_GOTO(ctc_acl_set_hash_field_sel(&acl_field_sel), ret, error3);
    
    return CTC_E_NONE;

error3:
    ctc_scl_uninstall_entry(scl_entry.entry_id);
error2: 
    ctc_scl_remove_entry(scl_entry.entry_id);
    return ret;
}


extern int32 sys_usw_qos_set_mc_queue_high_priority_en(uint8 lchip);
int32
ctc_app_pon_init(uint8 lchip, void* p_param)
{
    uint8 gchip = 0;
    uint8 index = 0;
    uint8 fid_mode = 0;
    uint8 vdev_mode = 0;
    uint16 vdev_index = 0;
    uint16 vdev_num = 0;
    uint16 vdev_base_vlan = 0;
    uint16 mc_tunnel_value = 0;
    uint16 bc_tunnel_value = 0;
    uint32 mcast_id = 0;
    ctc_app_pon_init_cfg_t* p_app_init = NULL;
    uint32 capability[CTC_GLOBAL_CAPABILITY_MAX] ={0};
    int32 ret = CTC_E_NONE;
    ctc_pon_global_cfg_t pon_global_cfg ;
    ctc_qos_queue_cfg_t que_cfg;

    if (NULL != p_app_pon_master)
    {
         return CTC_E_INIT_FAIL;
    }

    p_app_init = (ctc_app_pon_init_cfg_t*)p_param;
    if(NULL == p_app_init)
    {
        vdev_num = 1;
        vdev_base_vlan = 0;
        bc_tunnel_value = CTC_APP_PON_BCAST_TUNNEL_ID;
        mc_tunnel_value = CTC_APP_PON_MCAST_TUNNEL_ID;
    }
    else
    {
        CTC_APP_PON_VLAN_ID_CHECK(p_app_init->vdev_base_vlan + p_app_init->vdev_num);
        if(p_app_init->fid_mode > 1 || p_app_init->vdev_mode > 1)
        {
            return CTC_E_INVALID_PARAM;
        }
        if ((p_app_init->vdev_num == 1 && p_app_init->vdev_base_vlan))
        {
            CTC_APP_API_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "%s\n", \
            p_app_init->vdev_num == 1? "Vdev base vlan not support when vdev num is 1 .": "Vdev base vlan can not be 0 when vdev num is larger than 1");
            return CTC_E_INVALID_PARAM;
        }
        if(p_app_init->mcast_tunnel_vlan != 0xffff)
        {
            CTC_APP_PON_VLAN_ID_CHECK(p_app_init->mcast_tunnel_vlan);
        }

        if(p_app_init->bcast_tunnel_vlan == 0)
        {
            bc_tunnel_value = CTC_APP_PON_BCAST_TUNNEL_ID;
        }
        else
        {
            CTC_APP_PON_VLAN_ID_CHECK(p_app_init->bcast_tunnel_vlan);
            bc_tunnel_value = p_app_init->bcast_tunnel_vlan;
        }
        vdev_num = p_app_init->vdev_num;
        vdev_base_vlan = p_app_init->vdev_base_vlan;
        fid_mode = p_app_init->fid_mode;
        mc_tunnel_value = p_app_init->mcast_tunnel_vlan;
        vdev_mode = p_app_init->vdev_mode;
    }
    /*
    if ((vdev_num > CTC_APP_PON_MAX_VDEV_NUM) || (vdev_num == 0))
    {
        return CTC_E_INVALID_PARAM;
    }*/

    MALLOC_POINTER(ctc_app_pon_t, p_app_pon_master);
    if (NULL == p_app_pon_master)
    {
        return CTC_E_NO_MEMORY;
    }

    sal_memset(p_app_pon_master, 0, sizeof(ctc_app_pon_t));
    p_app_pon_master->vdev_num = vdev_num;
    p_app_pon_master->vdev_base_vlan = vdev_base_vlan;
    p_app_pon_master->fid_mode = fid_mode;
    p_app_pon_master->mcast_tunnel_vlan = mc_tunnel_value;
    p_app_pon_master->bcast_tunnel_vlan = bc_tunnel_value;
    p_app_pon_master->vdev_mode = vdev_mode;
        
    /*create mutex*/
    CTC_APP_PON_CREAT_LOCK(lchip);

    CTC_ERROR_GOTO(ctc_get_gchip_id(lchip, &gchip), ret, roll_back_0);

    ctc_app_index_init(gchip);

    CTC_ERROR_GOTO(ctc_app_index_set_chipset_type(gchip, CTC_APP_CHIPSET_CTC7132), ret, roll_back_0);

    CTC_ERROR_GOTO(ctc_global_ctl_get(CTC_GLOBAL_CHIP_CAPABILITY, capability), ret, roll_back_0);
    p_app_pon_master->mcast_max_group_num = capability[CTC_GLOBAL_CAPABILITY_MCAST_GROUP_NUM];

    /*------------DB------------*/
    CTC_ERROR_GOTO(_ctc_app_pon_init_db(lchip), ret, roll_back_0);

    CTC_ERROR_GOTO(_ctc_app_pon_init_opf(lchip, vdev_num), ret, roll_back_1);

    CTC_ERROR_GOTO(_ctc_app_pon_init_global_vdev(lchip, &mcast_id), ret, roll_back_2);

    for (vdev_index=0; vdev_index<vdev_num; vdev_index++)
    {
        CTC_ERROR_GOTO(_ctc_app_pon_init_port(lchip, vdev_index), ret, roll_back_3);
        p_app_pon_master->uni_inner_isolate_en[vdev_index] = 1;
    }
    CTC_ERROR_GOTO(_ctc_app_pon_alloc_mcast_group_id(lchip, CTC_APP_PON_MAX_RSV_MC_GROUP_ID, &mcast_id), ret, roll_back_3);

    sal_memset(&pon_global_cfg, 0, sizeof(pon_global_cfg));
    pon_global_cfg.mode = g_app_pon_mode;
    CTC_ERROR_GOTO(ctc_pon_init(&pon_global_cfg), ret, roll_back_4);

    sal_memset(&que_cfg, 0, sizeof(ctc_qos_queue_cfg_t));
    que_cfg.type = CTC_QOS_QUEUE_CFG_QUEUE_REASON_DEST;
    que_cfg.value.reason_dest.cpu_reason = CTC_PKT_CPU_REASON_PON_PT_PKT;
    que_cfg.value.reason_dest.dest_port = 0;
    que_cfg.value.reason_dest.dest_type = CTC_PKT_CPU_REASON_TO_DROP;
    ctc_qos_set_queue(&que_cfg);

    ctc_interrupt_register_event_cb(0, _ctc_app_pon_hw_learning_sync);
    ctc_interrupt_register_event_cb(1, _ctc_app_pon_hw_aging_sync);

    CTC_ERROR_GOTO(sys_usw_qos_set_mc_queue_high_priority_en(lchip), ret, roll_back_3);

    if(pon_global_cfg.mode)
    {
        CTC_ERROR_GOTO(_ctc_app_pon_init_mode(lchip), ret, roll_back_3);
    }
    return CTC_E_NONE;

roll_back_4:
    _ctc_app_pon_free_mcast_group_id(lchip, CTC_APP_PON_MAX_RSV_MC_GROUP_ID, mcast_id);
roll_back_3:
    for (index = 0; index < vdev_index; index++)
    {
        _ctc_app_pon_free_port(lchip, index);
    }
    _ctc_app_pon_free_global_vdev(lchip, mcast_id);

roll_back_2:
    _ctc_app_pon_free_opf(lchip);

roll_back_1:
    _ctc_app_pon_free_db(lchip);

roll_back_0:
    if (NULL != p_app_pon_master->mutex)
    {
        sal_mutex_destroy(p_app_pon_master->mutex);
    }
    FREE_POINTER(p_app_pon_master);

    return ret;
}

#endif
#endif
